- cd to backend
- IMPORTANT Copy the
.appsettings.Example.jsonfile, rename it to.appsettings.Development.json, then put in the proper api key from the discord/notion. - do
dotnet runin the console or if using Visual Studio, click the green Http button at the top (after opening the.slnfile) - cd to frontend
- do
npm install npx expo start- download the expo go app if you haven't
- scan qr code
- go crazy!!!!!!!!!!!
POST /api/users/login
POST /api/users/register
// the rest of these routes require a jwt token, which you can get from previous routes
GET /api/recipes
POST /api/recipes
DELETE /api/recipes/{recipeId}
GET /api/recipes/generate
GET /api/items
POST /api/items/manual-entry
DELETE /api/items/manual-remove/{itemId}
POST /api/items/update-expiry
POST /api/items/upload-image
Read on for more information.
Base URL (dev): https://localhost:7134
http://localhost:5100/api/users OR https://localhost:7134/api/users
Try to use https. Auth shouldnt even work on http lol.
All authentication uses JWT Bearer tokens.
Frontend calls POST /login or POST /register API returns a JWT token Frontend stores token
Frontend sends token on future requests:
Authorization: Bearer
Authenticate an existing user.
{
"email": "sharon@waterloo.com",
"password": "ilovenewjeans"
}
Password is sent plain-text over HTTPS. Hashing is handled server-side.
Success Response (200 OK)
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Invalid email or password
const res = await fetch("/api/users/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
});
if (!res.ok) throw new Error("Login failed");
const { token } = await res.json();
Register a new user and create their user profile.
This endpoint performs:
Auth user creation User profile creation Token issuance
{ "email": "sharon@waterloo.com", "password": "ilovenewjeans",
"preferredCuisines": ["Korean", "Japanese"], "groceryStoreFrequencyPerWeek": 2, "goals": ["High protein", "Muscle gain"], "restrictions": ["Peanuts"] }
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
Email already exists
Auth created but profile creation failed (should be rare)
const res = await fetch("/api/users/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
preferredCuisines,
groceryStoreFrequencyPerWeek,
goals,
restrictions,
}),
});
if (!res.ok) throw new Error("Registration failed");
const { token } = await res.json();
For all protected endpoints, include:
Authorization: Bearer <token>
await fetch("/api/some-protected-endpoint", {
headers: {
Authorization: `Bearer ${token}`,
},
});
In dev, the backend may be seeded with:
email: sharon@waterloo.com
password: ilovenewjeans
Fetch a user’s saved recipes
- Save a recipe for a user
- Remove a saved recipe
- Generate new recipes for a user
Get all saved recipes for a user. Success Response (200 OK)
[
{
"name": "Spicy Chicken Rice Bowl",
"ingredients": [
"Chicken breast",
"Rice",
"Gochujang",
"Soy sauce"
],
"instructions": [
"Cook rice",
"Marinate chicken",
"Pan fry chicken",
"Assemble bowl"
],
"preparationTimeMinutes": 15,
"cookingTimeMinutes": 20,
"cuisineType": "Korean",
"mealType": "Dinner",
"servings": 2,
"dietaryRestrictions": []
}
]
NOTE: this is a sample response. most likely each instruction and ingredient will have more information (amount, cook time, etc...)
await fetch(`/api/recipes`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
Save a recipe for a user.
Honestly not sure if this is necessary. This is just if you want the user to make a user submitted recipe for whatever reason
{
"name": "Avocado Toast",
"ingredients": [
"Bread",
"Avocado",
"Salt",
"Pepper"
],
"instructions": [
"Toast bread",
"Mash avocado",
"Spread on toast"
],
"preparationTimeMinutes": 5,
"cookingTimeMinutes": 3,
"cuisineType": "Western",
"mealType": "Breakfast",
"servings": 1,
"dietaryRestrictions": ["Vegan"]
}
(no body)
400 Bad Request Failed to save recipe
await fetch(`/api/recipes/save`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(recipe),
});
Remove a saved recipe for a user.
recipeId = GUID of the recipe.
should get this from after calling the GET /api/recipes endpoint
(no body)
400 Bad Request Failed to remove recipe
await fetch(`/api/recipes/${recipeId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
},
});
Generate new recipe suggestions for a user.
This endpoint:
- Uses the user’s preferences (cuisines, goals, restrictions, etc.)
- Returns generated recipes
userId = GUID of user
[
{
"name": "High-Protein Tofu Stir Fry",
"ingredients": [
"Tofu",
"Broccoli",
"Soy sauce",
"Garlic"
],
"instructions": [
"Press tofu",
"Stir fry vegetables",
"Add tofu and sauce"
],
"preparationTimeMinutes": 10,
"cookingTimeMinutes": 15,
"cuisineType": "Asian",
"mealType": "Dinner",
"servings": 2,
"dietaryRestrictions": ["Vegetarian"]
}
]
await fetch(`/api/recipes/${userId}/generate`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
Get all items currently associated with the authenticated user.
[
{
"id": "6f0a5b0e-7b1a-4c2f-9d8a-1f6c2b9a1234",
"userId": "9e2d3c4a-8f1a-4d9b-bb71-82c6a1f45678",
"name": "Milk",
"category": "Packaged",
"quantity": 1,
"recordedAt": "2026-02-02T18:41:00Z",
"expirationDate": "2026-02-10T00:00:00Z",
"detectedConfidence": 0.93
},
{
"id": "8c4f2a9d-5b11-4f7a-9dcb-0f3b12a98765",
"userId": "9e2d3c4a-8f1a-4d9b-bb71-82c6a1f45678",
"name": "Eggs",
"category": "Ingredient",
"quantity": 12,
"recordedAt": "2026-02-01T10:12:00Z",
"expirationDate": null,
"detectedConfidence": 0.0
}
]
don't really remember the format of the date. category = Ingredient, packaged, or a third item i forgot.
You can doublecheck theGeminiClient.csclass (our prompt is there too. should i hide the system prompt? probably...)
Example (fetch)
await fetch("/api/items", {
headers: {
Authorization: `Bearer ${token}`,
},
});
Manually add an item to the user’s inventory.
- itemName = name of item
- expiryDate = expiry date. this is optional
POST /api/items/manual-entry?itemName=Milk&expiryDate=2026-02-10
(no body)
await fetch(
`/api/items/manual-entry?itemName=Milk&expiryDate=2026-02-10`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
}
);
Remove an item from the user’s inventory.
itemId = ID of the item to remove
(no body)
Example (fetch)
await fetch(`/api/items/manual-remove/${itemId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
},
});
Recalculate or update expiry dates for all user items.
This endpoint:
- Re-evaluates item expiry dates
- Uses backend logic / heuristics
- Does not require any request body
(no body)
Example (fetch)
await fetch("/api/items/update-expiry", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});
Upload an image of groceries/items to automatically detect and update the user’s inventory.
This endpoint:
- Accepts a multipart/form-data request
- Uses AI/image recognition
- Adds or updates items for the user
multipart/form-data
image = the image
(no body)
const formData = new FormData();
formData.append("image", file);
await fetch("/api/items/upload-image", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: formData,
});