Cooked Customer API Spec
This API lets a customer-owned integration log in, search and manage saved recipes, and manage the customer's shopping list.
Base URL: https://cooked.wiki
All JSON requests should use:
Content-Type: application/json
Accept: application/json
Authentication
The API uses a Cooked session cookie for authenticated requests. Treat this cookie like a password: store it only in a trusted secret store, never log it, and never ask users to paste it into public or untrusted chats.
Send the session cookie with every authenticated /api/... request:
Cookie: <session-cookie-name>=<session-cookie-value>
There are two supported ways to obtain a session cookie.
Username/Password Login
Use this flow only for accounts that have password login enabled.
POST /api/public/login
{
"username": "customer_username",
"password": "customer_password"
}
Success:
{
"message": "Authenticated successfully",
"username": "customer_username"
}
Invalid login returns 401 with code: "INVALID_AUTHENTICATION".
On success, store the session cookie from the response and send it on future authenticated requests.
Browser Session Cookie
Use this flow for social-login or passwordless accounts, such as accounts that log in with Google, Facebook, or Apple.
- Ask the user to log in normally at
https://cooked.wiki/loginin their browser. - Ask the user to provide the Cooked session cookie for
https://cooked.wikithrough a trusted secret input. - Store that cookie as a secret and send it as the
Cookieheader on API requests.
The cookie is a bearer credential. Anyone with it can act as the logged-in user until it expires or is invalidated.
Expired Sessions
If an authenticated API request returns 401, discard the stored session cookie.
If username/password credentials are configured, retry POST /api/public/login once and then retry the original request with the new cookie. If the account uses social login or no password is available, prompt the user to log in in the browser again and provide a fresh Cooked session cookie through a trusted secret input.
Recipes
Recipe content is plain Markdown-style recipe text. Use recipeId values returned by list/search/create calls.
| Action | Endpoint | Notes |
|---|---|---|
| List recipes | GET /api/user/{username}/recipes?page=1&page-count=30 |
Returns saved recipe cards. |
| Search recipes | GET /api/user/{username}/recipes/search?q={query}&page=1 |
Searches the user's saved cookbook. |
| Get metadata | GET /api/recipe/{recipeId}/metadata |
Title, image URLs, owner, edit permission. |
| Get content | GET /api/recipe/{recipeId}/content |
Recipe body and portions. |
| Update content | POST /api/recipe/{recipeId}/content |
Updates recipe body and portions. |
| Delete recipe | DELETE /api/recipe/{recipeId} |
Removes a saved recipe. |
Recipe Card
List and search return recipe cards like:
{
"id": "recipe-id",
"title": "Pasta with Tomato Sauce",
"thumbnail-url": "https://..."
}
Recipe Content
GET /api/recipe/{recipeId}/content returns:
{
"content": "# Pasta with Tomato Sauce\n\n- 200g pasta\n- 1 cup tomato sauce\n\n1. Boil the pasta.",
"portions": 2
}
Update the recipe with:
{
"description": "# Updated Recipe\n\n- ingredient\n\n1. step",
"portions": 4
}
Success:
{
"message": "Recipe updated",
"code": "RECIPE_UPDATED"
}
Create Recipe From Text
Use this when the integration already has recipe text.
- Preview the recipe:
POST /api/new/from-text/preview
{
"recipe-name": "Pasta with Tomato Sauce",
"recipe-text": "Ingredients: 200g pasta, 1 cup tomato sauce. Steps: Boil pasta, warm sauce, combine."
}
The response includes title, markdown, and portions.
- Save the preview:
POST /api/recipe/import/save
{
"title": "Pasta with Tomato Sauce",
"description": "# Pasta with Tomato Sauce\n\n- 200g pasta\n- 1 cup tomato sauce\n\n1. Boil the pasta.",
"portions": 2
}
Success:
{
"recipe-id": "new-recipe-id"
}
Create Recipe From URL
Use this when the integration has a recipe URL.
POST /api/new
{
"url": "https://example.com/recipe"
}
The response may include either a saved recipe-id or an import draft extraction-id.
When an extraction-id is returned:
- Read the draft with
GET /api/recipe/{extractionId}/metadataandGET /api/recipe/{extractionId}/content. - Save it with
POST /api/extract/{extractionId}/save.
Save request:
{
"description": "# Imported Recipe\n\n- ingredient\n\n1. step",
"portions": 4
}
Success:
{
"recipe-id": "new-recipe-id"
}
Shopping List
The API accepts plain-text ingredients and returns organized shopping-list product groups. Use product group IDs from GET /api/user/{username}/shopping-list for updates and removals.
| Action | Endpoint | Notes |
|---|---|---|
| Add ingredients | PUT /api/user/shopping-list |
Adds one or more ingredients to the logged-in user's list. |
| Get list | GET /api/user/{username}/shopping-list |
Returns aisles and product groups. |
| Update item | PUT /api/user/{username}/shopping-list/product-groups/{productGroupId} |
Updates name, quantity, aisle, or selected state. |
| Mark selected | PUT /api/user/{username}/shopping-list/product-groups/selection |
Replaces the complete selected/purchased set. |
| Remove items | DELETE /api/user/{username}/shopping-list/product-groups |
Removes product groups by ID. |
| Clear list | DELETE /api/user/{username}/shopping-list |
Clears all shopping-list items. |
Add Ingredients
{
"ingredients": "200g pasta\n1 cup tomato sauce\nParmesan cheese",
"recipe-id": "optional-recipe-id"
}
recipe-id is optional and may be a saved recipe ID or an import draft ID.
Success:
{
"success": true,
"added-count": 3,
"ingredients": [
"200g pasta",
"1 cup tomato sauce",
"Parmesan cheese"
]
}
Shopping List Response
{
"success": true,
"username": "customer_username",
"shopping-list": {
"aisles": [
{
"aisle-id": "pantry",
"aisle-name": "Pantry",
"product-groups": [
{
"id": "product-group-id",
"name": "Pasta",
"quantity": "200g",
"selected": false
}
]
}
]
},
"recipes": [
"recipe-id"
]
}
Update Shopping List Item
Send all editable fields:
{
"name": "Pasta",
"quantity": "250g",
"aisle-id": "pantry",
"selected": false
}
Success:
{
"success": true
}
Mark Purchased Items
selected is the full list of product group IDs that should be marked selected/purchased. Items not included are marked unselected.
{
"selected": [
"product-group-id-1",
"product-group-id-2"
]
}
Remove Shopping List Items
{
"ids": [
"product-group-id-1",
"product-group-id-2"
]
}
Common Errors
| Status | Meaning |
|---|---|
400 |
Invalid or missing request data. |
401 |
Not logged in or invalid credentials. |
403 |
Logged in but not allowed to edit this resource. |
404 |
Recipe, draft, or shopping-list item not found. |
Example:
{
"message": "Recipe not found",
"code": "RECIPE_NOT_FOUND"
}