Base development URL:
http://localhost:4000
For Android emulator:
http://10.0.2.2:4000For iOS simulator:
http://127.0.0.1:4000
All requests and responses use JSON.
Errors always follow this format:
{
"error": "Human readable message"
}POST /plans
{
"startDate": "2025-02-01",
"days": [
{ "date": "2025-02-01", "meals": ["Lunch", "Dinner"] },
{ "date": "2025-02-02", "meals": ["Lunch"] }
]
}{
"id": "PLAN_ID",
"startDate": "2025-02-01",
"days": [
{
"date": "2025-02-01",
"meals": ["Lunch", "Dinner"]
}
]
}GET /plans/:planId
{
"id": "PLAN_ID",
"startDate": "2025-02-01",
"days": [
{
"date": "2025-02-01",
"meals": [
"Lunch",
{ "label": "Dinner", "recipeId": "RECIPE_ID" }
]
}
]
}POST /plans/:planId/meals/saved
{
"date": "2025-02-01",
"label": "Lunch",
"recipeId": "RECIPE_ID"
}Same shape as GET /plans/:planId
POST /plans/:planId/meals/ai
{
"date": "2025-02-01",
"label": "Dinner",
"preferences": {
"num_people": 2,
"time_available": 45,
"dietary_restrictions": [],
"preferences_text": "Moroccan"
}
}Updated plan with recipe added.
GET /recipes
[
{
"id": "RECIPE_ID",
"title": "Moroccan Beef Stew",
"ingredients": ["1 onion", "2 tomatoes"],
"steps": ["Step 1", "Step 2"],
"prep_time": 15,
"cook_time": 30,
"source": "ai"
}
]POST /shopping-list/:planId
{
"planId": "PLAN_ID",
"items": [
{
"name": "tomatoes",
"lines": [
"2 tomatoes",
"200g chopped tomatoes"
]
},
{
"name": "onion",
"lines": ["1 onion"]
}
]
}Backend internally calls:
POST http://localhost:8000/ai/suggest-meal
POST http://localhost:8000/ai/extract-recipe
Frontend does NOT call those directly.
import { createPlan, addAiMealToPlan, getShoppingList } from "./api";
const plan = await createPlan({
startDate: "2025-02-01",
days: [
{ date: "2025-02-01", meals: ["Lunch", "Dinner"] }
]
});
const updated = await addAiMealToPlan(plan.id, {
date: "2025-02-01",
label: "Dinner",
preferences: { preferences_text: "Italian" }
});
const list = await getShoppingList(plan.id);
console.log(list);