Core API
Recipes
Generate, list, and manage structured recipes. Generation is the flagship endpoint: it turns a set of constraints into a complete recipe with ingredients, instructions, macros, and tags.
Endpoints
/v1/recipesList recipes under your account/v1/recipes/{uuid}Retrieve a stored recipe/v1/recipes/generateGenerate a new AI recipe/v1/recipes/{uuid}/generate-variationBranch a stored recipe you own (healthy/budget)/v1/recipes/callbackAsync callback receiver (signed)/v1/recipes/{uuid}Hard-delete (Sanctum/app token only)Identifying recipes
uuid, the stable public identifier returned by GET /v1/recipes and GET /v1/recipes/{uuid}. Use it for GET, DELETE, and POST /v1/recipes/{uuid}/generate-variation. The id returned in a POST /v1/recipes/generate response is a throwaway per-request client handle for the mobile client. Generation is stateless, so pass "save": true to persist the recipe and receive its real uuid.List recipes under your account
GET /v1/recipes
Returns every recipe owned by the identity behind your key (the API key's owning user). Paginated with ?per_page= (1-100, default 20).
{
"data": [
{
"uuid": "9b1c2d7e-...-4a3f",
"title": "One-Pan Indian Chicken & Rice",
"cuisine": "indian",
"difficulty": "Medium",
"servings": 2,
"prep_time_minutes": 10,
"cook_time_minutes": 20,
"instructions": ["Brown the chicken...", "Add spices...", "Simmer 18 min."],
"nutrition_info": { "calories": 520, "protein_g": 38, "carbs_g": 48, "fat_g": 14 },
"tags": ["indian", "gluten-free", "one-pan"],
"is_favorite": false,
"created_at": "2026-07-03T18:02:11.000000Z",
"ingredients": [
{ "name": "chicken thigh", "quantity": "400", "unit": "g", "is_optional": false, "was_substituted": false }
]
}
],
"meta": { "total": 42, "per_page": 20, "current_page": 1, "last_page": 3 }
}Retrieve a single recipe
GET /v1/recipes/{uuid}
Returns one stored recipe by uuid, scoped to your account. A recipe you don't own returns 404.
Generate a recipe
POST /v1/recipes/generate
The request body mirrors the Dishora mobile wizard: ingredients, available pantry, cuisine, dietary restrictions, allergies, time, skill level, servings, instruction style, and budget. Generation is synchronous: the response returns the complete recipe in one call, typically within a few seconds.
{
"ingredients": ["chicken", "rice", "tomato"],
"available_ingredients": ["onion", "garlic", "cumin"],
"cuisine": "indian",
"dietary_restrictions": ["gluten-free"],
"allergies": [],
"time_available": 30,
"skill_level": "comfortable",
"servings": 2,
"instruction_style": "normal",
"health_mode": "regular",
"budget": "standard",
"meal_type": "dinner",
"use_pantry_only": false,
"save": false
}Branch a recipe (healthy / budget / method variation)
POST /v1/recipes/{uuid}/generate-variation
Generates a variation (healthy or budget) of a recipe you own, scoped to the calling identity. The new recipe is stored as a child of the parent (linked via parent_uuid) and the response returns the new recipe plus variation_type and the new recipe_uuid.
{
"variation_type": "healthy",
"health_focus": "highProtein",
"tone": "normal",
"dietary_restrictions": ["dairy-free"],
"allergies": ["peanuts"]
}variation_type is required and must be healthy, budget, or method. health_focus applies to healthy variations only and accepts general, highProtein, gutHealth, heartHealthy, or diabeticFriendly. With method, pass target_method (stovetop, oven, pressure_cooker, slow_cooker, air_fryer, grill) to rewrite the recipe for a different appliance. tone, dietary_restrictions, and allergies are forwarded to the AI but not strictly validated.
Errors
404: no recipe with thatuuid, or it isn't owned by the calling identity.422:variation_typemust behealthy,budget, ormethod(with a validtarget_method).429: rate limited.500:{ "error": "Failed to generate variation. Please try again." }.
Persist on generate (opt-in)
"save": true in the request body (or ?save=true) to have the API store the generated recipe under your account. The response then additionally includes the real uuid, so you can immediately call POST /v1/recipes/{uuid}/generate-variation or GET /v1/recipes/{uuid} without a separate lookup. Without save, generation stays stateless (the id in the response is a throwaway client handle for the mobile app).Where recipes actually live
recipes table through one of two paths:- Collections: adding a recipe to a collection (
POST /collections/{id}/recipes) upserts the full recipe payload server-side. This is how the app persists recipes it wants to keep across devices. - Developer API: calling
POST /v1/recipes/generatewith"save": truestores the recipe under the key's owning account.
POST /sync endpoint only reconciles is_favorite and image URIs by uuid. It never creates recipes.Key parameters
ingredients: must-have focus ingredients (max 30).available_ingredients: pantry items that may also be used (max 200).time_available: minutes (1-480), or a preset:superQuick,quick,standard,relaxed,leisurely,iHaveTime.servings: 1-20.skill_level:beginner|comfortable|advanced.instruction_style:normal|funny|romantic|motivational|minimal|detailed|brief|step_by_step. (toneis accepted as an alias.)health_mode:regular|healthy|light.budget:standard|budget.craving_mode:exact(make the requested dish) |creative(use it as inspiration).use_pantry_only: restrict the recipe to the provided ingredients plus basic staples.save: persist the recipe and return its realuuid.
Caching