Cookest
Backend APIsEndpoints

Recipes

App API recipe browsing, favouriting, rating, and cook tracking

Recipes

These endpoints live on the App API. The standalone Food API exposes /api/v1/recipes for the catalog service.

GET /api/recipes

Search and browse the recipe catalog.

MethodPathAuthTier
GET/api/recipesOptional JWTFree

Query parameters

ParameterTypeDescription
qstringFull-text search query
categorystringFilter by cuisine (e.g. italian, asian)
difficultystringeasy | medium | hard
max_timeintegerMax total time in minutes
dietarystringDietary filter (e.g. vegetarian, vegan, gluten_free)
limitintegerMax results (default: 20)
offsetintegerPagination offset

Response 200 OK

{
  "items": [
    {
      "id": "uuid",
      "title": "Pasta Carbonara",
      "description": "Classic Roman pasta dish",
      "cuisine": "italian",
      "difficulty": "medium",
      "prep_time": 10,
      "cook_time": 20,
      "servings": 4,
      "calories": 520,
      "is_favourite": false,
      "rating_avg": 4.3,
      "rating_count": 12,
      "image_url": "https://..."
    }
  ],
  "total": 150,
  "limit": 20,
  "offset": 0
}

GET /api/recipes/:id

Get full recipe details including ingredients and steps.

MethodPathAuthTier
GET/api/recipes/:idOptional JWTFree

Response 200 OK

{
  "id": "uuid",
  "title": "Pasta Carbonara",
  "description": "Classic Roman pasta dish",
  "cuisine": "italian",
  "difficulty": "medium",
  "prep_time": 10,
  "cook_time": 20,
  "servings": 4,
  "is_favourite": false,
  "rating_avg": 4.3,
  "rating_count": 12,
  "ingredients": [
    {
      "ingredient_id": 1,
      "name": "Spaghetti",
      "quantity": 400,
      "unit": "g"
    }
  ],
  "steps": [
    {
      "step_number": 1,
      "instruction": "Boil salted water and cook spaghetti until al dente."
    }
  ],
  "nutrition": {
    "calories": 520,
    "protein": 22,
    "carbs": 68,
    "fat": 18,
    "fiber": 3
  },
  "images": ["https://..."]
}

POST /api/recipes

Create a new recipe. Pro or Family tier required.

MethodPathAuthTier
POST/api/recipesJWT BearerPro

Request body

{
  "title": "My Special Pasta",
  "description": "A family favourite",
  "cuisine": "italian",
  "difficulty": "easy",
  "prep_time": 15,
  "cook_time": 30,
  "servings": 4,
  "ingredients": [
    { "ingredient_id": 1, "quantity": 400, "unit": "g" }
  ],
  "steps": [
    { "step_number": 1, "instruction": "Cook pasta." }
  ]
}

Response 201 Created

Returns the created recipe object with id.


PUT /api/recipes/:id

Update a recipe. Only the recipe's owner or an admin may update.

MethodPathAuthTier
PUT/api/recipes/:idJWT BearerPro

Same body as POST. Returns the updated recipe.


DELETE /api/recipes/:id

Delete a recipe. Only the owner or admin may delete.

MethodPathAuthTier
DELETE/api/recipes/:idJWT BearerPro

Response 204 No Content


POST /api/recipes/:id/favourite

Bookmark a recipe.

MethodPathAuthTier
POST/api/recipes/:id/favouriteJWT BearerFree

Response 200 OK

{ "is_favourite": true }

DELETE /api/recipes/:id/favourite

Remove a recipe bookmark.

MethodPathAuthTier
DELETE/api/recipes/:id/favouriteJWT BearerFree

Response 200 OK

{ "is_favourite": false }

POST /api/recipes/:id/rate

Rate a recipe (1–5 stars).

MethodPathAuthTier
POST/api/recipes/:id/rateJWT BearerFree

Request body

{
  "rating": 5,
  "notes": "Absolutely delicious!"
}

Response 200 OK

Returns the updated aggregate rating.


POST /api/recipes/:id/cook

Record that the user cooked this recipe. Triggers inventory deduction.

MethodPathAuthTier
POST/api/recipes/:id/cookJWT BearerFree

Request body

{
  "servings": 2
}

Response 200 OK

{
  "cooked_at": "2024-01-20T18:30:00Z",
  "inventory_updated": true,
  "ingredients_deducted": 4
}

POST /api/recipes/generate

Generate a new recipe draft with AI. Pro tier required.

MethodPathAuthTier
POST/api/recipes/generateJWT BearerPro

Request body

{
  "prompt": "high-protein breakfast with eggs",
  "use_pantry": true,
  "cuisine_hint": "Italian",
  "max_minutes": 30
}
FieldTypeNotes
promptstringFree-text recipe request from the user
use_pantrybooleanPrefer pantry ingredients when generating
cuisine_hintstring | nullOptional cuisine/style steering
max_minutesinteger | nullOptional total time cap

Response 200 OK

{
  "name": "Frittata al Parmigiano",
  "description": "A fluffy baked egg dish...",
  "cuisine": "Italian",
  "difficulty": "easy",
  "prep_minutes": 10,
  "cook_minutes": 20,
  "servings": 2,
  "ingredients": [
    { "name": "eggs", "quantity": 4.0, "unit": "pieces", "is_pantry_item": true },
    { "name": "parmesan", "quantity": 50.0, "unit": "g", "is_pantry_item": false }
  ],
  "steps": ["Preheat oven to 180°C", "Beat eggs with seasoning", "..."],
  "macros_per_serving": {
    "calories": 320,
    "protein_g": 24,
    "carbs_g": 4,
    "fat_g": 22,
    "fiber_g": 0
  },
  "tags": ["high-protein", "breakfast", "gluten-free"],
  "score": {
    "overall": 0.88,
    "palatability": 0.91,
    "nutrition_balance": 0.84,
    "preference_match": 0.89,
    "palatability_reason": "Well-balanced flavors with good protein content",
    "iterations": 2
  }
}

Score object

FieldMeaning
overallBest combined score chosen by the refinement loop
palatabilityHow appealing the recipe is expected to be to eat
nutrition_balanceMacro and nutrition quality signal
preference_matchFit against dietary preferences and user context
palatability_reasonShort explanation for the taste/appeal score
iterationsHow many generate/score/refine passes were needed

The server runs a generate → score → refine loop for up to 3 iterations and returns the best result. When use_pantry is true, pantry items are preferred and matching ingredients are flagged with is_pantry_item: true.

On this page