# Tiny Plates: the full documentation > Tiny Plates is a recipe API and MCP server for apps and AI agents, with a free plan. It serves thousands of recipes from across the web in one structured model: parsed ingredients with quantities and units, numbered steps, times, servings, nutrition, diets and allergen flags, in English, Spanish and Swedish. - REST API base URL: https://api.tinyplates.dev, authenticated with an API key sent as a bearer token. Free accounts get 50 requests a day and 300 a week. Paid plans start at $5 a month: https://www.tinyplates.dev/pricing - OpenAPI 3.1 description: https://api.tinyplates.dev/openapi.json - MCP server (streamable HTTP, OAuth sign-in or API key): https://api.tinyplates.dev/mcp - Sign up for a key: https://www.tinyplates.dev/sign-up - Recipes belong to their publishers. Credit the source and link to the `source.url` a recipe carries. AI agents and LLM apps may call the API at run time; for training on the recipes or bulk access, contact us first. - Every page on https://www.tinyplates.dev has a Markdown copy at its address plus ".md" (the landing page is /index.md). https://www.tinyplates.dev/llms-full.txt has the documentation in one file. --- title: "Introduction — Tiny Plates recipe API" description: "A read API for thousands of recipes from across the web, in one model: structured ingredients, numbered steps, times in seconds, nutrition and media." url: "https://www.tinyplates.dev/docs" --- # Tiny Plates API A read API for thousands of recipes scraped from the web and normalized into one model. Every public recipe has structured ingredients, numbered steps, times in seconds, servings, nutrition, media, classification and whether it contains each regulated allergen. ## Base URL Every endpoint hangs off one host. There is no version prefix in the path; the current model is version 2 and is described by the [OpenAPI document](https://api.tinyplates.dev/openapi.json). ``` https://api.tinyplates.dev ``` ## Your first request [Create a key](https://www.tinyplates.dev/docs/authentication) — it takes a minute and comes with 50 requests a day — then ask for the most popular recipe. ``` curl 'https://api.tinyplates.dev/popular?limit=1' \ -H 'Authorization: Bearer rd_your_api_key' ``` The [quickstart](https://www.tinyplates.dev/docs/quickstart) walks through a real request and its response, in curl, JavaScript and Python. ## Endpoints 9 endpoints, all `GET`, none of which take a request body. * [GET/searchSearch recipes by meaning as well as wording, across names, ingredients and descriptions, and return only the fields you need.](https://www.tinyplates.dev/docs/api/search-recipes) * [GET/popularThe best-loved recipes in the database, ranked by rating and by how many people rated them, so one five-star review cannot beat a long-loved favourite.](https://www.tinyplates.dev/docs/api/popular-recipes) * [GET/recipes/{id}Fetch a single recipe by its id, with structured ingredients, numbered steps, times, nutrition and media, scaled to the number of servings you ask for.](https://www.tinyplates.dev/docs/api/get-recipe) * [GET/pantryRank recipes by how much of them your pantry already covers, with the missing ingredients listed, so you can see what you can cook right now.](https://www.tinyplates.dev/docs/api/pantry-recipes) * [GET/shopping-listTurn several recipes and their serving counts into one shopping list, grouped by aisle, with the amounts of shared ingredients added together.](https://www.tinyplates.dev/docs/api/shopping-list) * [GET/recipesBusiness planBusiness plan only. Page through the whole database, newest first, filtered by cuisine, course, category, diet, ingredient, language or total time.](https://www.tinyplates.dev/docs/api/list-recipes) * [GET/substitutionsWhat to use instead of an ingredient, in what amount and how to handle it, and when the swap does not work. An ingredient with no known swap gets no guess.](https://www.tinyplates.dev/docs/api/substitutions) * [GET/ingredientsThe canonical ingredient vocabulary, most used first, with every spelling seen per language, so "tomat", "Tomate" and "tomato" resolve to one id.](https://www.tinyplates.dev/docs/api/list-ingredients) * [GET/vocabulariesThe closed lists recipes are classified with: cuisines, courses, diets, EU and US regulated allergen features, and units. Fetch them once and cache them.](https://www.tinyplates.dev/docs/api/vocabularies) ## Conventions * Responses are JSON. Errors are always `{ error: { message } }` — see [errors](https://www.tinyplates.dev/docs/errors). * Durations are seconds, never formatted strings. Timestamps are ISO 8601. * A field that is absent is unknown, not empty. The API omits what a source did not publish rather than guessing at it. * `cuisines`, `courses`, diets, regulated allergen features and units come from closed lists — see [filtering and vocabularies](https://www.tinyplates.dev/docs/filtering). * List endpoints page with `limit` and `offset` — see [pagination](https://www.tinyplates.dev/docs/pagination). --- title: "Quickstart — Tiny Plates recipe API" description: "Make your first request to the Tiny Plates recipe API in curl, JavaScript or Python, then read the recipes, ingredients and steps it sends back." url: "https://www.tinyplates.dev/docs/quickstart" --- # Quickstart From nothing to a recipe in three steps. ## Get a key Create an account, then create a key on your [dashboard](https://www.tinyplates.dev/dashboard/keys). [Authentication](https://www.tinyplates.dev/docs/authentication) covers the rest. ## Search for a recipe Search matches on meaning as well as wording, so this finds carbonara as readily as anything with “creamy” in the title. Replace `rd_your_api_key` with the key you just created. ``` curl 'https://api.tinyplates.dev/search?query=creamy+pasta&limit=3' \ -H 'Authorization: Bearer rd_your_api_key' ``` ## Read the response Every result is a full recipe plus a `score`. Times are seconds, ingredients are parsed into quantities and names, and steps are numbered. This is the same object every recipe endpoint returns — see [the recipe object](https://www.tinyplates.dev/docs/recipe-object). When you only need a few fields, ask for them. The response then carries those, plus `id` and `score`: ``` curl 'https://api.tinyplates.dev/search?query=creamy+pasta&limit=3&fields=title,url,times' \ -H 'Authorization: Bearer rd_your_api_key' ``` ## Where to go next * [Filtering and vocabularies](https://www.tinyplates.dev/docs/filtering) — narrow a list by cuisine, course, diet, ingredient or total time. * [Pagination](https://www.tinyplates.dev/docs/pagination) — page through popular or pantry results. * [Errors](https://www.tinyplates.dev/docs/errors) — every message the API can answer with, and what to do about it. * [The API reference](https://www.tinyplates.dev/docs/api/search-recipes) — every endpoint, with a Run button. --- title: "Authentication — Tiny Plates recipe API" description: "How API keys work: creating one in the dashboard, sending it as a bearer token, and what the API answers when a key is missing or revoked." url: "https://www.tinyplates.dev/docs/authentication" --- # Authentication The API is authenticated with keys. A key belongs to one account and can be revoked at any time. The allowances belong to the account, not the key. ## Creating a key Sign in and create a key on your [dashboard](https://www.tinyplates.dev/dashboard/keys). Keys start with `rd_`. **The full key is shown once.** Only a hash of it is stored, so it cannot be shown again — if you lose it, revoke it and create another. The dashboard lists the first few characters so you can tell your keys apart. ## Sending a key Send it as a bearer token in the `Authorization` header: ``` curl 'https://api.tinyplates.dev/search?query=pasta&limit=3' \ -H 'Authorization: Bearer rd_your_api_key' ``` That is the only header the API documents. The key goes in a header and never in the query string, so it stays out of logs, browser history and shared links. ## When a key is refused * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. ## Looking after a key * Keep keys server-side. Anything in a browser bundle or a mobile app is public, and a key there is a key anyone can spend. * Use a key per application, so revoking one does not take the others down with it, and so the usage chart tells you which is which. * Revoking is immediate. The next request with that key is refused. Usage is counted per key per day and shown on your [dashboard](https://www.tinyplates.dev/dashboard/usage), but the daily and weekly allowances are spent by the account as a whole. See [rate limits](https://www.tinyplates.dev/docs/rate-limits) for what happens at the ceiling. --- title: "Use from your agent — Tiny Plates recipe API" description: "Connect Claude Code, Codex, Cursor, VS Code, Gemini CLI or any MCP client to Tiny Plates, sign in with your account, and let your agent search recipes." url: "https://www.tinyplates.dev/docs/mcp" --- # Use from your agent The API is also an MCP server, so an agent such as Claude, ChatGPT, Claude Code or Cursor can search recipes, cook from a pantry and build shopping lists on its own. You sign in with your Tiny Plates account; there is no key to copy. ## Connecting The server speaks streamable HTTP at one URL: ``` https://api.tinyplates.dev/mcp ``` Pick your agent: 1. In Claude on the web or desktop, open Customize → Connectors, choose Add custom connector, and paste the server URL: ``` https://api.tinyplates.dev/mcp ``` 2. Choose Connect, then sign in with your Tiny Plates account. ## Signing in The first time the agent connects, it opens Tiny Plates in your browser. Sign in — or [create an account](https://www.tinyplates.dev/sign-up) — and allow the agent access. It keeps the sign-in and renews it on its own; you are asked again only if you remove the server. Every tool call is one API request. It counts toward your usage alongside your API keys, shows up in your usage on the [dashboard](https://www.tinyplates.dev/dashboard/usage), and is subject to the same [rate limits](https://www.tinyplates.dev/docs/rate-limits). ## With an API key Where a browser sign-in is not possible, such as a CI job or a shared machine, send an [API key](https://www.tinyplates.dev/docs/authentication) as a bearer token instead. Each agent above shows how under _Use an API key instead_. Keys start with `rd_` and are created on your [dashboard](https://www.tinyplates.dev/dashboard/keys). ## Pagination A whole recipe is thousands of characters, and an agent reads every result into its context. So the tools that return recipes answer at most 5 at a time, however large a `limit` the agent sends: * [cook\_from\_pantry](https://www.tinyplates.dev/docs/mcp#tool-cook%5Ffrom%5Fpantry) * [find\_recipes](https://www.tinyplates.dev/docs/mcp#tool-find%5Frecipes) * [popular\_recipes](https://www.tinyplates.dev/docs/mcp#tool-popular%5Frecipes) * [search\_recipes](https://www.tinyplates.dev/docs/mcp#tool-search%5Frecipes) A list response carries `pagination.total`, the number of recipes that match; the agent asks for the next page by passing `offset`. `search_recipes` ranks by relevance and has no offset: a sharper query is the way to more results. ## Errors A call the API refuses — a parameter out of range, a recipe id that does not exist, an allowance spent — comes back as a tool error carrying the API’s own message, which says what to change. The agent reads it and tries again. Each tool below links to its endpoint, where the errors are listed; the [errors](https://www.tinyplates.dev/docs/errors) page explains them all. A missing or expired sign-in is answered before any tool runs, with a `401` that tells the agent to sign in again. ## Tools Every tool reads; none of them changes anything. Each one calls one endpoint of the API and answers with that endpoint’s response, so the REST reference and this one describe the same data. ### build\_shopping\_list Build a shopping list Build one shopping list from several recipes, grouped by aisle, with quantities added up across recipes. A recipe asked for at a different serving count is scaled first. A line may also carry extras: amounts a recipe asked for in a unit its quantity cannot take, such as the 3 tbsp in "1 cup + 3 tbsp". They are not folded into quantity, so buy them as well. Parameters * `recipes`string\[\]required 1 to 20 recipe ids from a search or list result, each optionally followed by ":" and the servings to cook, such as "66d0a1b2c3d4e5f6a7b8c9d0:6". Returns The JSON the [Build a shopping list](https://www.tinyplates.dev/docs/api/shopping-list) endpoint answers with. `items[]`object\[\] `category`string The aisle: bakery, dairy, drinks, frozen, meat, other, pantry, produce, seafood or spices. `display`string The line as a reader would write it. `extras`object\[\]optional Amounts a recipe asked for in a unit the quantity cannot take, one per unit, such as the 3 tbsp in "1 cup + 3 tbsp". Buy them as well as the quantity. `name`string The ingredient name. `plusMore`booleanoptional Present when a recipe also asked for this without saying how much — oil for frying, a garnish — so the quantity is a minimum rather than the whole of it. `quantity`objectoptional The amount to buy. Absent when no recipe gave one, such as "salt to taste". `recipeIds`string\[\] The ids of the recipes that asked for it. The list, grouped by aisle and then by name. `recipes[]`object\[\] `id`string The recipe id. `servings`number The servings the recipe was scaled to. `title`string The recipe title. The recipes the list was built from, in the order they were asked for, with the servings each was scaled to. Example response ``` { "items": [ { "category": "dairy", "display": "250 ml double cream", "name": "double cream", "quantity": { "unit": "ml", "value": 250 }, "recipeIds": [ "6a9820a88f8122ec891b680b" ] }, { "category": "dairy", "display": "1 cup + 3 tbsp pecorino romano", "extras": [ { "unit": "tbsp", "value": 3 } ], "name": "pecorino romano", "quantity": { "unit": "cup", "value": 1 }, "recipeIds": [ "6a9820e58f8122ec891b68a4" ] }, { "category": "meat", "display": "1.2 kg chicken thighs", "name": "chicken thighs", "quantity": { "unit": "kg", "value": 1.2 }, "recipeIds": [ "6a9820a88f8122ec891b680b", "6a9820e58f8122ec891b68a4" ] }, { "category": "produce", "display": "5 onion", "name": "onion", "quantity": { "value": 5 }, "recipeIds": [ "6a9820a88f8122ec891b680b", "6a9820e58f8122ec891b68a4" ] }, { "category": "spices", "display": "salt", "name": "salt", "recipeIds": [ "6a9820e58f8122ec891b68a4" ] } ], "recipes": [ { "id": "6a9820a88f8122ec891b680b", "servings": 6, "title": "Chicken Tikka Masala" }, { "id": "6a9820e58f8122ec891b68a4", "servings": 4, "title": "Slow-Roasted Cherry Tomatoes" } ] } ``` ### cook\_from\_pantry Cook from your pantry Find what you can cook from the ingredients you have, best covered first. Each recipe lists the pantry ingredients it uses and the ones you are missing; maxMissing: 0 returns what you can cook right now. Common staples — salt, pepper, water, oil, sugar, flour — are assumed to be on hand: they are left out of the coverage and of missingIngredients and returned in assumedIngredients instead. Send staples: false to count them as ingredients you need. Parameters * `ingredients`string\[\]required The ingredients you have. 1 to 20 names or canonical ids from list\_ingredients, such as "chicken" or "chicken-thigh". * `language`string Only recipes written in this language, as a two-letter ISO 639-1 code such as "en" or "sv". * `limit`integer How many recipes to return, 1–5\. Defaults to 5. * `maxMissing`integer Only recipes missing at most this many ingredients, 0–20\. Left out, any number may be missing. * `offset`integer How many recipes to skip, to fetch the next page. The response’s pagination.total says how many match. * `staples`string Whether salt, pepper, water, oil, sugar and flour count as already in the kitchen. Defaults to true; false counts them as ingredients you need. * `without`string\[\] Leave out recipes that contain any of these allergen features from list\_vocabularies, such as "milk" or "peanuts". Informational, not a medical guarantee. Returns The JSON the [Cook from your pantry](https://www.tinyplates.dev/docs/api/pantry-recipes) endpoint answers with, 5 recipes at a time. `pagination`object `limit`integer How many recipes this response holds. Capped at 100. `offset`integer How many were skipped. `total`integer How many match the filter in total. Offset pagination. `recipes[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. `assumedIngredients`string\[\] The staples the recipe uses, taken as already in your kitchen. Empty when "staples=false". `coverage`number The share of the recipe's ingredients your pantry covers, from 0 to 1, rounded to two decimals. Staples are in neither half of it. `matchedIngredients`string\[\] The recipe ingredients your pantry covers. `missingIngredients`string\[\] The recipe ingredients your pantry does not cover. The recipes, best covered first. Example response ``` { "pagination": { "limit": 1, "offset": 0, "total": 112 }, "recipes": [ { "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "id": "6a9820e58f8122ec891b68a3", "author": { "name": "Lindsay Ostrom", "url": "https://pinchofyum.com/about" }, "description": "This peanut butter dark chocolate hummus is a sweet alternative to traditional hummus. Perfect served on graham crackers as an afternoon snack!", "instructions": [ { "group": "Hummus", "step": 1, "text": "Blend everything through milk in a food processor." }, { "group": "Hummus", "step": 2, "text": "Add flour by the spoonful and blend until desired consistency is reached." }, { "step": 3, "text": "Stir in dark chocolate." }, { "step": 4, "text": "Chill before serving." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=225%2C225", "variants": [ { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=195%2C195" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=180%2C180" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg" } ] } ], "notes": [ "Keeps in an airtight container in the fridge for up to five days.", "Swap the peanut butter for almond butter to make it peanut free." ], "nutrition": { "basis": { "description": "¼ cup", "servings": 8, "type": "serving" }, "calories": { "unit": "kcal", "value": 201 }, "carbohydrates": { "unit": "g", "value": 29.4 }, "cholesterol": { "unit": "mg", "value": 0.8 }, "fat": { "unit": "g", "value": 7.4 }, "fiber": { "unit": "g", "value": 3.3 }, "micronutrients": { "trans-fat": { "unit": "g", "value": 0 } }, "protein": { "unit": "g", "value": 5.6 }, "saturatedFat": { "unit": "g", "value": 2.5 }, "sodium": { "unit": "mg", "value": 76 }, "source": "provided", "sugar": { "unit": "g", "value": 16.9 } }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "max": 8, "original": "6-8", "quantity": 6 }, "times": { "cook": { "seconds": 600 }, "prep": { "seconds": 300 }, "total": { "seconds": 900 } }, "title": "Peanut Butter Dark Chocolate Hummus", "categories": [], "courses": [ "dessert" ], "createdAt": "2026-09-02T13:13:09.089Z", "cuisines": [ "american" ], "groups": [ "Hummus" ], "ingredients": [ { "display": "1 can white beans or chickpeas, rinsed", "name": "white beans or chickpeas", "optional": false, "original": "1 can white beans or chickpeas, rinsed", "preparation": "rinsed", "quantity": { "unit": "can", "value": 1 } }, { "display": "¼ cup peanut butter", "name": "peanut butter", "optional": false, "original": "¼ cup peanut butter", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "2 tbsp caramel sauce", "name": "caramel sauce", "optional": false, "original": "2 tbsp caramel sauce", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 tbsp maple syrup", "name": "maple syrup", "optional": false, "original": "2 tbsp maple syrup", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "¼ cup brown sugar", "name": "brown sugar", "optional": false, "original": "¼ cup brown sugar", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "pinch of cinnamon", "name": "pinch of cinnamon", "optional": false, "original": "pinch of cinnamon" }, { "display": "¼ cup milk", "name": "milk", "optional": false, "original": "¼ cup milk", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "¼ cup flour", "name": "flour", "optional": false, "original": "¼ cup flour", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "chopped dark chocolate", "name": "chopped dark chocolate", "optional": false, "original": "chopped dark chocolate" } ], "tags": [ "chocolate hummus", "peanut butter hummus", "peanut butter chocolate", "hummus recipe", "dessert hummus" ], "text": { "ingredients": [ "1 can white beans or chickpeas, rinsed", "¼ cup peanut butter", "2 tbsp caramel sauce", "2 tbsp maple syrup", "¼ cup brown sugar", "pinch of cinnamon", "¼ cup milk", "¼ cup flour", "chopped dark chocolate" ], "instructions": [ "Blend everything through milk in a food processor.", "Add flour by the spoonful and blend until desired consistency is reached.", "Stir in dark chocolate.", "Chill before serving." ] }, "updatedAt": "2026-09-06T01:11:59.223Z", "url": "https://pinchofyum.com/pb-dark-chocolate-hummus", "assumedIngredients": [ "flour" ], "coverage": 0.75, "matchedIngredients": [ "white beans or chickpeas", "peanut butter", "maple syrup", "brown sugar", "pinch of cinnamon", "milk" ], "missingIngredients": [ "caramel sauce", "chopped dark chocolate" ] } ] } ``` ### find\_recipes Find recipes List recipes newest first, filtered by any combination of cuisine, course, category, diet, ingredients, allergens, equipment, time and nutrition. Use search\_recipes instead to search by meaning. Allowed cuisines, courses and diets come from list\_vocabularies. Parameters * `category`string A category slug such as "pasta" or "soup", as a recipe's categories field carries it. * `course`string A course from list\_vocabularies, such as "main-course". * `cuisine`string A cuisine from list\_vocabularies, such as "italian". * `diet`string A diet from list\_vocabularies, such as "vegetarian". Matches recipes the site declared it for and recipes whose required ingredients suit it; recipes not known to suit it are excluded. An inferred "gluten-free" or "dairy-free" reads the required ingredients only, so it can be stated where the allergen block, which counts optional and serving lines too, stays cautious. * `equipment`string\[\] Equipment every recipe must use, such as "air fryer" or "slow cooker". * `excludeIngredients`string\[\] Leave out recipes using any of these ingredient names or ids. Not an allergen guarantee. * `ingredients`string\[\] Ingredient names or ids every recipe must use. * `language`string Only recipes written in this language, as a two-letter ISO 639-1 code such as "en" or "sv". * `limit`integer How many recipes to return, 1–5\. Defaults to 5. * `maxCalories`integer Maximum kilocalories per serving. * `maxCookMinutes`integer Maximum cooking time in minutes. * `maxSodium`integer Maximum milligrams of sodium per serving. * `maxTotalMinutes`integer Maximum total time in minutes. * `minFiber`integer Minimum grams of fiber per serving. * `minProtein`integer Minimum grams of protein per serving. * `nutrition`string\[\] Nutrition presets: "high-fiber", "high-protein", "low-calorie", "low-sodium". * `offset`integer How many recipes to skip, to fetch the next page. The response’s pagination.total says how many match. * `time`string A total-time preset: "under-15", "under-30" or "weekend". * `without`string\[\] Leave out recipes that contain any of these allergen features from list\_vocabularies, such as "milk" or "peanuts". Informational, not a medical guarantee. Returns The JSON the [List recipes](https://www.tinyplates.dev/docs/api/list-recipes) endpoint answers with, 5 recipes at a time. `pagination`object `limit`integer How many recipes this response holds. Capped at 100. `offset`integer How many were skipped. `total`integer How many match the filter in total. Offset pagination. `recipes[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. The matching recipes. Example response ``` { "pagination": { "limit": 2, "offset": 0, "total": 1930 }, "recipes": [ { "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "id": "6a9820e58f8122ec891b68a3", "author": { "name": "Lindsay Ostrom", "url": "https://pinchofyum.com/about" }, "description": "This peanut butter dark chocolate hummus is a sweet alternative to traditional hummus. Perfect served on graham crackers as an afternoon snack!", "instructions": [ { "group": "Hummus", "step": 1, "text": "Blend everything through milk in a food processor." }, { "group": "Hummus", "step": 2, "text": "Add flour by the spoonful and blend until desired consistency is reached." }, { "step": 3, "text": "Stir in dark chocolate." }, { "step": 4, "text": "Chill before serving." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=225%2C225", "variants": [ { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=195%2C195" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=180%2C180" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg" } ] } ], "notes": [ "Keeps in an airtight container in the fridge for up to five days.", "Swap the peanut butter for almond butter to make it peanut free." ], "nutrition": { "basis": { "description": "¼ cup", "servings": 8, "type": "serving" }, "calories": { "unit": "kcal", "value": 201 }, "carbohydrates": { "unit": "g", "value": 29.4 }, "cholesterol": { "unit": "mg", "value": 0.8 }, "fat": { "unit": "g", "value": 7.4 }, "fiber": { "unit": "g", "value": 3.3 }, "micronutrients": { "trans-fat": { "unit": "g", "value": 0 } }, "protein": { "unit": "g", "value": 5.6 }, "saturatedFat": { "unit": "g", "value": 2.5 }, "sodium": { "unit": "mg", "value": 76 }, "source": "provided", "sugar": { "unit": "g", "value": 16.9 } }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "max": 8, "original": "6-8", "quantity": 6 }, "times": { "cook": { "seconds": 600 }, "prep": { "seconds": 300 }, "total": { "seconds": 900 } }, "title": "Peanut Butter Dark Chocolate Hummus", "categories": [], "courses": [ "dessert" ], "createdAt": "2026-09-02T13:13:09.089Z", "cuisines": [ "american" ], "groups": [ "Hummus" ], "ingredients": [ { "display": "1 can white beans or chickpeas, rinsed", "name": "white beans or chickpeas", "optional": false, "original": "1 can white beans or chickpeas, rinsed", "preparation": "rinsed", "quantity": { "unit": "can", "value": 1 } }, { "display": "¼ cup peanut butter", "name": "peanut butter", "optional": false, "original": "¼ cup peanut butter", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "2 tbsp caramel sauce", "name": "caramel sauce", "optional": false, "original": "2 tbsp caramel sauce", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 tbsp maple syrup", "name": "maple syrup", "optional": false, "original": "2 tbsp maple syrup", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "¼ cup brown sugar", "name": "brown sugar", "optional": false, "original": "¼ cup brown sugar", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "pinch of cinnamon", "name": "pinch of cinnamon", "optional": false, "original": "pinch of cinnamon" }, { "display": "¼ cup milk", "name": "milk", "optional": false, "original": "¼ cup milk", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "¼ cup flour", "name": "flour", "optional": false, "original": "¼ cup flour", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "chopped dark chocolate", "name": "chopped dark chocolate", "optional": false, "original": "chopped dark chocolate" } ], "tags": [ "chocolate hummus", "peanut butter hummus", "peanut butter chocolate", "hummus recipe", "dessert hummus" ], "text": { "ingredients": [ "1 can white beans or chickpeas, rinsed", "¼ cup peanut butter", "2 tbsp caramel sauce", "2 tbsp maple syrup", "¼ cup brown sugar", "pinch of cinnamon", "¼ cup milk", "¼ cup flour", "chopped dark chocolate" ], "instructions": [ "Blend everything through milk in a food processor.", "Add flour by the spoonful and blend until desired consistency is reached.", "Stir in dark chocolate.", "Chill before serving." ] }, "updatedAt": "2026-09-06T01:11:59.223Z", "url": "https://pinchofyum.com/pb-dark-chocolate-hummus" }, { "id": "6a9820e58f8122ec891b68a4", "description": "Slow-roasted cherry tomatoes are intensely sweet and tangy. Add them to salads, pastas, pizza and more.", "instructions": [ { "step": 1, "text": "Preheat the oven to 275°F (135°C) and set an oven rack in the middle position. Line a baking sheet with wide heavy-duty aluminum foil." }, { "step": 2, "text": "Directly on the lined baking sheet, using a rubber spatula, toss the tomatoes with the olive oil, vinegar, sugar, salt, pepper, and garlic. Roast for 2 hours, until the tomatoes are soft and beginning to burst. Serve hot or at room temperature." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes.jpg", "variants": [ { "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes-500x500.jpg" }, { "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes-500x375.jpg" }, { "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes-480x270.jpg" } ] } ], "nutrition": { "basis": { "type": "serving" }, "calories": { "unit": "kcal", "value": 117 }, "carbohydrates": { "unit": "g", "value": 8 }, "fat": { "unit": "g", "value": 9 }, "fiber": { "unit": "g", "value": 2 }, "protein": { "unit": "g", "value": 1 }, "saturatedFat": { "unit": "g", "value": 1 }, "sodium": { "unit": "mg", "value": 388 }, "source": "provided", "sugar": { "unit": "g", "value": 6 } }, "rating": { "count": 25, "reviewCount": 8, "value": 4.8 }, "servings": { "original": "6", "quantity": 6 }, "times": { "cook": { "seconds": 7200 }, "prep": { "seconds": 600 }, "total": { "seconds": 7800 } }, "title": "Roasted Cherry Tomatoes", "categories": [ "vegetables-and-sides" ], "courses": [ "appetizer", "side-dish" ], "createdAt": "2026-09-02T13:13:09.118Z", "cuisines": [ "italian" ], "groups": [], "ingredients": [ { "display": "2 lb cherry tomatoes (3 pints)", "name": "cherry tomatoes", "note": "3 pints", "optional": false, "original": "2 lb cherry tomatoes (3 pints)", "quantity": { "unit": "lb", "value": 2 } }, { "display": "¼ cup extra-virgin olive oil", "name": "extra-virgin olive oil", "optional": false, "original": "¼ cup extra-virgin olive oil", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "1½ tbsp balsamic vinegar", "name": "balsamic vinegar", "optional": false, "original": "1½ tbsp balsamic vinegar", "quantity": { "unit": "tbsp", "value": 1.5 } }, { "display": "2 tsp sugar", "name": "sugar", "optional": false, "original": "2 tsp sugar", "quantity": { "unit": "tsp", "value": 2 } }, { "display": "1 tsp salt", "name": "salt", "optional": false, "original": "1 tsp salt", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "½ tsp freshly ground black pepper", "name": "freshly ground black pepper", "optional": false, "original": "½ tsp freshly ground black pepper", "quantity": { "unit": "tsp", "value": 0.5 } }, { "display": "2 clove garlic (minced)", "name": "garlic", "note": "minced", "optional": false, "original": "2 clove garlic (minced)", "quantity": { "unit": "clove", "value": 2 } } ], "tags": [ "roasted cherry tomatoes" ], "text": { "ingredients": [ "2 lb cherry tomatoes (3 pints)", "¼ cup extra-virgin olive oil", "1½ tbsp balsamic vinegar", "2 tsp sugar", "1 tsp salt", "½ tsp freshly ground black pepper", "2 clove garlic (minced)" ], "instructions": [ "Preheat the oven to 275°F (135°C) and set an oven rack in the middle position. Line a baking sheet with wide heavy-duty aluminum foil.", "Directly on the lined baking sheet, using a rubber spatula, toss the tomatoes with the olive oil, vinegar, sugar, salt, pepper, and garlic. Roast for 2 hours, until the tomatoes are soft and beginning to burst. Serve hot or at room temperature." ] }, "updatedAt": "2026-09-06T01:11:59.224Z", "url": "https://www.onceuponachef.com/recipes/slow-roasted-cherry-tomatoes.html" } ] } ``` ### find\_substitutions Find substitutions What to use instead of an ingredient: how much of each substitute to use for one unit of the original, how to handle it, and what it cannot be used for. Ingredients nothing is known to replace come back in unknown. Parameters * `ingredients`string\[\]required The ingredients to replace. 1 to 20 names or canonical ids from list\_ingredients, such as "chicken" or "chicken-thigh". Returns The JSON the [Ingredient substitutions](https://www.tinyplates.dev/docs/api/substitutions) endpoint answers with. `substitutions[]`object\[\] `ingredient`string The ingredient asked about, normalized. `options`object\[\] The substitutes, each with \`ingredient\`, \`ratio\` (how much to use for one unit of the original), an optional \`note\` on handling it, and an optional \`caution\` saying what it cannot be used for. One entry per ingredient that has substitutions. `unknown`string\[\] The ingredients nothing is known to substitute for. Nothing is suggested for them. Example response ``` { "substitutions": [ { "ingredient": "butter", "options": [ { "caution": "Not for creaming into a batter or for pastry, where solid fat is what makes the texture.", "ingredient": "olive oil", "note": "Use three quarters as much. The result is softer and does not brown the same way.", "ratio": 0.75 }, { "ingredient": "margarine", "note": "Use a block, not a spread: spreads carry more water.", "ratio": 1 } ] } ], "unknown": [ "saffron" ] } ``` ### get\_recipe Get a recipe Fetch one recipe in full — structured ingredients, numbered steps, times and nutrition — optionally scaled to a number of servings or converted to metric or imperial units. Parameters * `id`stringrequired The recipe id, from a search or list result. * `servings`integer Rewrite every quantity for this many servings, 1–100. * `units`string Convert the recipe to these units. One of: metric, imperial. Returns The JSON the [Get a recipe](https://www.tinyplates.dev/docs/api/get-recipe) endpoint answers with. `conversion`objectoptional `system`string The system the recipe was rewritten in. `unweighed`string\[\] Ingredients measured by volume that could not be weighed, because no density is known for them. Their lines keep the unit the source wrote them in. What the unit conversion did. Present only when \`units\` was given. `nutritionTotals`objectoptional `basisServings`number The serving count perRecipe was multiplied up from: the label's own basis when the recipe declares one — a recipe stored as serving 8 to 10 can carry a label worked out on 10, not the stored 8 — otherwise the serving count the recipe had before any scaling. `perRecipe`object Nutrition for the whole recipe. `perServing`object Nutrition for one serving. `servings`number The serving count both figures were worked out from. The same nutrition told twice: for one serving, which is what recipes are compared on, and for the whole recipe, which is what the cook is making. Present only when the recipe carries nutrition and says how many servings it makes; figures published per 100 g cannot be split this way and are left out. Scaling with \`servings\` changes the whole-recipe figures and leaves the per-serving ones alone. `recipe`object `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. The recipe. Example response ``` { "recipe": { "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "id": "6a9820e58f8122ec891b68a3", "author": { "name": "Lindsay Ostrom", "url": "https://pinchofyum.com/about" }, "description": "This peanut butter dark chocolate hummus is a sweet alternative to traditional hummus. Perfect served on graham crackers as an afternoon snack!", "instructions": [ { "group": "Hummus", "step": 1, "text": "Blend everything through milk in a food processor." }, { "group": "Hummus", "step": 2, "text": "Add flour by the spoonful and blend until desired consistency is reached." }, { "step": 3, "text": "Stir in dark chocolate." }, { "step": 4, "text": "Chill before serving." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=225%2C225", "variants": [ { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=195%2C195" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=180%2C180" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg" } ] } ], "notes": [ "Keeps in an airtight container in the fridge for up to five days.", "Swap the peanut butter for almond butter to make it peanut free." ], "nutrition": { "basis": { "description": "¼ cup", "servings": 8, "type": "serving" }, "calories": { "unit": "kcal", "value": 201 }, "carbohydrates": { "unit": "g", "value": 29.4 }, "cholesterol": { "unit": "mg", "value": 0.8 }, "fat": { "unit": "g", "value": 7.4 }, "fiber": { "unit": "g", "value": 3.3 }, "micronutrients": { "trans-fat": { "unit": "g", "value": 0 } }, "protein": { "unit": "g", "value": 5.6 }, "saturatedFat": { "unit": "g", "value": 2.5 }, "sodium": { "unit": "mg", "value": 76 }, "source": "provided", "sugar": { "unit": "g", "value": 16.9 } }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "max": 8, "original": "6-8", "quantity": 6 }, "times": { "cook": { "seconds": 600 }, "prep": { "seconds": 300 }, "total": { "seconds": 900 } }, "title": "Peanut Butter Dark Chocolate Hummus", "categories": [], "courses": [ "dessert" ], "createdAt": "2026-09-02T13:13:09.089Z", "cuisines": [ "american" ], "groups": [ "Hummus" ], "ingredients": [ { "display": "1 can white beans or chickpeas, rinsed", "name": "white beans or chickpeas", "optional": false, "original": "1 can white beans or chickpeas, rinsed", "preparation": "rinsed", "quantity": { "unit": "can", "value": 1 } }, { "display": "¼ cup peanut butter", "name": "peanut butter", "optional": false, "original": "¼ cup peanut butter", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "2 tbsp caramel sauce", "name": "caramel sauce", "optional": false, "original": "2 tbsp caramel sauce", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 tbsp maple syrup", "name": "maple syrup", "optional": false, "original": "2 tbsp maple syrup", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "¼ cup brown sugar", "name": "brown sugar", "optional": false, "original": "¼ cup brown sugar", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "pinch of cinnamon", "name": "pinch of cinnamon", "optional": false, "original": "pinch of cinnamon" }, { "display": "¼ cup milk", "name": "milk", "optional": false, "original": "¼ cup milk", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "¼ cup flour", "name": "flour", "optional": false, "original": "¼ cup flour", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "chopped dark chocolate", "name": "chopped dark chocolate", "optional": false, "original": "chopped dark chocolate" } ], "tags": [ "chocolate hummus", "peanut butter hummus", "peanut butter chocolate", "hummus recipe", "dessert hummus" ], "text": { "ingredients": [ "1 can white beans or chickpeas, rinsed", "¼ cup peanut butter", "2 tbsp caramel sauce", "2 tbsp maple syrup", "¼ cup brown sugar", "pinch of cinnamon", "¼ cup milk", "¼ cup flour", "chopped dark chocolate" ], "instructions": [ "Blend everything through milk in a food processor.", "Add flour by the spoonful and blend until desired consistency is reached.", "Stir in dark chocolate.", "Chill before serving." ] }, "updatedAt": "2026-09-06T01:11:59.223Z", "url": "https://pinchofyum.com/pb-dark-chocolate-hummus" } } ``` ### list\_ingredients List ingredients The canonical ingredient vocabulary, most used first. Its ids are what the ingredient filters take, and every spelling seen per language resolves to one of them. Parameters * `limit`integer How many results to return, 1–500\. Defaults to 100. Returns The JSON the [List ingredients](https://www.tinyplates.dev/docs/api/list-ingredients) endpoint answers with. `ingredients[]`object\[\] `aliases`object Every spelling seen, keyed by two-letter language code. `id`string The canonical id, such as "chicken-thigh". `names`object The canonical name, keyed by two-letter language code. `recipeCount`integer How many recipes use this ingredient. The ingredients, most used first. Example response ``` { "ingredients": [ { "aliases": { "en": [ "salt", "sea salt", "kosher salt", "salt and black pepper", "salt and pepper" ], "de": [ "Salz", "Jodsalz", "Bad Reichenhaller MarkenJodSalz mit Fluorid und Folsäure" ], "sv": [ "salt", "salt och svartpeppar", "salt och peppar", "flingsalt" ], "es": [ "sal", "Sal" ] }, "id": "salt", "names": { "en": "salt" }, "recipeCount": 783 }, { "aliases": { "en": [ "black pepper", "freshly ground black pepper" ], "de": [ "Pfeffer", "schwarzer Pfeffer", "frisch gemahlener Pfeffer", "gemahlener Pfeffer", "grober schwarzer Pfeffer" ], "sv": [ "peppar", "svartpeppar", "nymalen svartpeppar", "malen vitpeppar", "svartpepparkorn" ], "es": [ "pimienta", "pimienta negra molida", "Pimienta negra molida" ] }, "id": "black-pepper", "names": { "en": "black pepper" }, "recipeCount": 451 }, { "aliases": { "en": [ "garlic", "garlic clove", "garlic cloves" ], "de": [ "Knoblauchzehe", "Knoblauchzehen" ], "sv": [ "vitlöksklyfta", "vitlöksklyftor", "vitlök" ], "es": [ "Dientes de ajo", "ajo" ] }, "id": "garlic", "names": { "en": "garlic" }, "recipeCount": 411 } ] } ``` ### list\_vocabularies List vocabularies The closed lists recipes are classified with: the cuisines, courses and diets find\_recipes accepts, EU and US regulated allergen features with their jurisdictions, and the units a quantity can carry. Parameters This tool takes no parameters. Returns The JSON the [Vocabularies](https://www.tinyplates.dev/docs/api/vocabularies) endpoint answers with. `allergens`object\[\] The 16 EU and US regulated allergen features and their applicable jurisdictions. `courses`string\[\] The values the \`course\` filter accepts. `cuisines`string\[\] The values the \`cuisine\` filter accepts. `diets`string\[\] The values the \`diet\` filter accepts. `units`string\[\] The units a quantity can carry. Example response ``` { "allergens": [ { "feature": "celery", "jurisdictions": [ "eu" ] }, { "feature": "crustaceans", "jurisdictions": [ "eu", "us" ] }, { "feature": "eggs", "jurisdictions": [ "eu", "us" ] }, { "feature": "fish", "jurisdictions": [ "eu", "us" ] }, { "feature": "gluten-cereals", "jurisdictions": [ "eu" ] }, { "feature": "lupin", "jurisdictions": [ "eu" ] }, { "feature": "milk", "jurisdictions": [ "eu", "us" ] }, { "feature": "molluscs", "jurisdictions": [ "eu" ] }, { "feature": "mustard", "jurisdictions": [ "eu" ] }, { "feature": "nuts-eu", "jurisdictions": [ "eu" ] }, { "feature": "peanuts", "jurisdictions": [ "eu", "us" ] }, { "feature": "sesame", "jurisdictions": [ "eu", "us" ] }, { "feature": "soy", "jurisdictions": [ "eu", "us" ] }, { "feature": "sulphites", "jurisdictions": [ "eu" ] }, { "feature": "tree-nuts-us", "jurisdictions": [ "us" ] }, { "feature": "wheat", "jurisdictions": [ "us" ] } ], "courses": [ "appetizer", "breakfast", "brunch", "dessert", "dinner", "drink", "lunch", "main-course", "side-dish", "snack" ], "cuisines": [ "african", "american", "argentinian", "asian", "australian", "austrian", "belgian", "brazilian", "british", "cajun", "caribbean", "chinese", "cuban", "danish", "dutch", "eastern-european", "egyptian", "ethiopian", "filipino", "finnish", "french", "german", "greek", "hungarian", "indian", "indonesian", "iranian", "irish", "israeli", "italian", "jamaican", "japanese", "korean", "latin-american", "lebanese", "malaysian", "mediterranean", "mexican", "middle-eastern", "moroccan", "norwegian", "pakistani", "peruvian", "polish", "portuguese", "russian", "scandinavian", "southern-us", "spanish", "swedish", "swiss", "tex-mex", "thai", "turkish", "vietnamese" ], "diets": [ "dairy-free", "gluten-free", "pescatarian", "vegan", "vegetarian" ], "units": [ "g", "kg", "lb", "oz", "cl", "cup", "dl", "fl-oz", "gallon", "l", "ml", "pint", "quart", "tbsp", "tsp", "bag", "bottle", "box", "bunch", "can", "clove", "cube", "dash", "drop", "ear", "handful", "head", "jar", "knob", "leaf", "package", "packet", "piece", "pinch", "portion", "pot", "scoop", "sheet", "shot", "slice", "sprig", "stalk", "stick", "tub", "cm", "inch" ] } ``` ### popular\_recipes Popular recipes The best-loved recipes, ranked by rating and by how many people rated them. Parameters * `language`string Only recipes written in this language, as a two-letter ISO 639-1 code such as "en" or "sv". * `limit`integer How many recipes to return, 1–5\. Defaults to 5. * `offset`integer How many recipes to skip, to fetch the next page. The response’s pagination.total says how many match. Returns The JSON the [Popular recipes](https://www.tinyplates.dev/docs/api/popular-recipes) endpoint answers with, 5 recipes at a time. `pagination`object `limit`integer How many recipes this response holds. Capped at 100. `offset`integer How many were skipped. `total`integer How many match the filter in total. Offset pagination. `recipes[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. `popularityScore`number How popular this recipe is relative to the others in this response. Higher comes first. The recipes, most popular first. Example response ``` { "pagination": { "limit": 1, "offset": 0, "total": 1848 }, "recipes": [ { "id": "6a9820a88f8122ec891b680b", "description": "No canning, no fuss—just crisp, tangy pickles you’ll want to eat with everything!", "instructions": [ { "step": 1, "text": "Combine the vinegar, salt and sugar in a small non-reactive saucepan (such as stainless steel, glass, ceramic or teflon) over high heat. Whisk until the salt and sugar are dissolved. Transfer the liquid into a bowl and whisk in the cold water. Refrigerate brine until ready to use." }, { "step": 2, "text": "Stuff the cucumbers into two clean 1 qt (1L) jars. Add the coriander seeds, garlic cloves, mustard seeds, red pepper flakes, dill sprigs, and chilled brine into jars, dividing evenly. If necessary, add a bit of cold water to the jars until the brine covers the cucumbers. Cover and refrigerate about 24 hours, then serve. The pickles will keep in the refrigerator for up to one month." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://www.onceuponachef.com/images/2012/04/pickles.jpg", "variants": [ { "url": "https://www.onceuponachef.com/images/2012/04/pickles-500x500.jpg" }, { "url": "https://www.onceuponachef.com/images/2012/04/pickles-500x375.jpg" }, { "url": "https://www.onceuponachef.com/images/2012/04/pickles-480x270.jpg" } ] } ], "rating": { "count": 517, "reviewCount": 11, "value": 4.93 }, "servings": { "original": "2 (1-qt) jars (about 24 spears)", "quantity": 2 }, "times": { "cook": { "seconds": 300 }, "prep": { "seconds": 900 }, "total": { "seconds": 1200 } }, "title": "Quick & Easy Refrigerator Pickles", "categories": [], "courses": [ "snack" ], "createdAt": "2026-09-02T13:12:08.379Z", "cuisines": [ "american" ], "groups": [], "ingredients": [ { "display": "1¼ cup distilled white vinegar (5% acidity)", "name": "distilled white vinegar", "note": "5% acidity", "optional": false, "original": "1¼ cup distilled white vinegar (5% acidity)", "quantity": { "unit": "cup", "value": 1.25 } }, { "display": "3 tbsp kosher salt", "name": "kosher salt", "optional": false, "original": "3 tbsp kosher salt", "quantity": { "unit": "tbsp", "value": 3 } }, { "display": "2 tbsp sugar", "name": "sugar", "optional": false, "original": "2 tbsp sugar", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 cup cold water", "name": "cold water", "optional": false, "original": "2 cup cold water", "quantity": { "unit": "cup", "value": 2 } }, { "display": "1¾-2 lb Kirby cucumbers, cut into halves or spears (about 6)", "name": "Kirby cucumbers", "note": "about 6", "optional": false, "original": "1¾-2 lb Kirby cucumbers, cut into halves or spears (about 6)", "preparation": "cut into halves or spears", "quantity": { "max": 2, "unit": "lb", "value": 1.75 } }, { "display": "2 tbsp coriander seeds", "name": "coriander seeds", "optional": false, "original": "2 tbsp coriander seeds", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "6 large garlic cloves (peeled and halved)", "name": "garlic cloves", "note": "peeled and halved", "optional": false, "original": "6 large garlic cloves (peeled and halved)", "quantity": { "value": 6 }, "size": "large" }, { "display": "1 tsp mustard seeds", "name": "mustard seeds", "optional": false, "original": "1 tsp mustard seeds", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "¼ tsp crushed red pepper flakes", "name": "crushed red pepper flakes", "optional": false, "original": "¼ tsp crushed red pepper flakes", "quantity": { "unit": "tsp", "value": 0.25 } }, { "display": "16 dill sprigs", "name": "dill sprigs", "optional": false, "original": "16 dill sprigs", "quantity": { "value": 16 } } ], "tags": [ "pickles" ], "text": { "ingredients": [ "1¼ cup distilled white vinegar (5% acidity)", "3 tbsp kosher salt", "2 tbsp sugar", "2 cup cold water", "1¾-2 lb Kirby cucumbers, cut into halves or spears (about 6)", "2 tbsp coriander seeds", "6 large garlic cloves (peeled and halved)", "1 tsp mustard seeds", "¼ tsp crushed red pepper flakes", "16 dill sprigs" ], "instructions": [ "Combine the vinegar, salt and sugar in a small non-reactive saucepan (such as stainless steel, glass, ceramic or teflon) over high heat. Whisk until the salt and sugar are dissolved. Transfer the liquid into a bowl and whisk in the cold water. Refrigerate brine until ready to use.", "Stuff the cucumbers into two clean 1 qt (1L) jars. Add the coriander seeds, garlic cloves, mustard seeds, red pepper flakes, dill sprigs, and chilled brine into jars, dividing evenly. If necessary, add a bit of cold water to the jars until the brine covers the cucumbers. Cover and refrigerate about 24 hours, then serve. The pickles will keep in the refrigerator for up to one month." ] }, "updatedAt": "2026-09-06T01:11:59.030Z", "url": "https://www.onceuponachef.com/recipes/quick-and-easy-dill-pickles.html", "popularityScore": 4.89536312849162 } ] } ``` ### search\_recipes Search recipes Search recipes by meaning as well as wording across names, ingredients and descriptions, so "creamy pasta" also finds carbonara. Best matches first. Parameters * `fields`string\[\] Only return these recipe fields, such as "title", "url" and "times", to keep results small. id and score are always included. * `language`string Only recipes written in this language, as a two-letter ISO 639-1 code such as "en" or "sv". * `limit`integer How many recipes to return, 1–5\. Defaults to 5. * `query`stringrequired What to search for. * `without`string\[\] Leave out recipes that contain any of these allergen features from list\_vocabularies, such as "milk" or "peanuts". Informational, not a medical guarantee. Returns The JSON the [Search recipes](https://www.tinyplates.dev/docs/api/search-recipes) endpoint answers with, 5 recipes at a time. `results[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. `score`number A rank fusion of the meaning and the wording legs of the search, plus a bonus for a title that contains the query. Higher comes first. It is a rank, not a confidence: scores are comparable only within one response. The matching recipes, best first. When \`fields\` is set, only the requested fields plus \`id\` and \`score\` are present. Example response ``` { "results": [ { "id": "6a980d75ea7517554c2894b1", "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "createdAt": "2026-09-02T11:50:13.886Z", "dietary": { "glutenFree": true, "vegetarian": true }, "instructions": [ { "equipment": [ "oven" ], "step": 1, "temperature": { "unit": "F", "value": 325 }, "text": "Preheat oven to 325°." }, { "ingredients": [ "roma-tomato" ], "step": 2, "techniques": [ "slicing" ], "text": "Slice tomatoes in half." }, { "ingredients": [ "salt", "basil", "oregano", "thyme" ], "step": 3, "techniques": [ "seasoning" ], "text": "Season with salt, basil, oregano and thyme." }, { "equipment": [ "baking-sheet" ], "ingredients": [ "olive-oil", "roma-tomato" ], "step": 4, "techniques": [ "spraying" ], "text": "Spray a cookie sheet with olive oil spray and place tomatoes cut side up." }, { "duration": { "seconds": 7200 }, "equipment": [ "oven" ], "ingredients": [ "roma-tomato" ], "step": 5, "techniques": [ "baking" ], "text": "Bake 2 hrs until skin gets wrinkled and crusty on the bottom and moist in the center." }, { "equipment": [ "food-processor" ], "ingredients": [ "roma-tomato" ], "step": 6, "techniques": [ "pureeing" ], "text": "Puree the tomatoes in a food processor." }, { "step": 7, "text": "If it is too thick, you can thin with pasta water." }, { "ingredients": [ "roma-tomato" ], "step": 8, "text": "Serve over your favorite high fiber pasta and grated cheese." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://www.skinnytaste.com/wp-content/uploads/2008/08/roasted-tomatoe-sauce.jpg", "variants": [ { "url": "https://www.skinnytaste.com/wp-content/uploads/2008/08/roasted-tomatoe-sauce-425x270.jpg" } ] } ], "nutrition": { "basis": { "type": "serving" }, "calories": { "unit": "kcal", "value": 78.1 }, "carbohydrates": { "unit": "g", "value": 17.3 }, "fat": { "unit": "g", "value": 1.2 }, "fiber": { "unit": "g", "value": 4.1 }, "protein": { "unit": "g", "value": 3.2 }, "source": "provided" }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "original": "4 servings", "quantity": 4 }, "times": {}, "title": "Candied Tomato Sauce", "updatedAt": "2026-09-06T01:39:14.527Z", "categories": [], "courses": [], "cuisines": [ "italian" ], "groups": [], "ingredients": [ { "display": "12 ripe Roma tomatoes", "localName": "Roma tomatoes", "ingredientId": "roma-tomato", "name": "Roma tomato", "optional": false, "original": "12 ripe Roma tomatoes", "quantity": { "value": 12 }, "size": "ripe" }, { "display": "salt", "localName": "salt", "ingredientId": "salt", "name": "salt", "note": "to taste", "optional": false, "original": "salt to taste" }, { "display": "1 tsp thyme", "localName": "thyme", "ingredientId": "thyme", "name": "thyme", "optional": false, "original": "1 tsp thyme", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "1 tsp oregano", "localName": "oregano", "ingredientId": "oregano", "name": "oregano", "optional": false, "original": "1 tsp oregano", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "olive oil spray", "localName": "olive oil", "ingredientId": "olive-oil", "name": "olive oil", "optional": false, "original": "olive oil spray", "preparation": "spray" }, { "display": "2 tbsp basil, chopped", "localName": "basil", "ingredientId": "basil", "name": "basil", "optional": false, "original": "2 tbsp basil, chopped", "preparation": "chopped", "quantity": { "unit": "tbsp", "value": 2 } } ], "tags": [ "freezer meals", "gluten free", "vegetarian meals" ], "text": { "ingredients": [ "12 ripe Roma tomatoes", "salt", "1 tsp thyme", "1 tsp oregano", "olive oil spray", "2 tbsp basil, chopped" ], "instructions": [ "Preheat oven to 325°.", "Slice tomatoes in half.", "Season with salt, basil, oregano and thyme.", "Spray a cookie sheet with olive oil spray and place tomatoes cut side up.", "Bake 2 hrs until skin gets wrinkled and crusty on the bottom and moist in the center.", "Puree the tomatoes in a food processor.", "If it is too thick, you can thin with pasta water.", "Serve over your favorite high fiber pasta and grated cheese." ] }, "url": "https://www.skinnytaste.com/candied-tomato-sauce-0-ww-pts/", "equipment": [ "baking sheet", "food processor", "oven" ], "techniques": [ "baking", "pureeing", "seasoning", "slicing", "spraying" ], "score": 0.0333 } ] } ``` --- title: "The recipe object — Tiny Plates recipe API" description: "The recipe object the API returns, field by field: ingredients, instructions, times, servings, nutrition, dietary flags, allergen evidence and media." url: "https://www.tinyplates.dev/docs/recipe-object" --- # The recipe object Recipes are scraped from sites that publish them however they like, then normalized into one object. This is that object. ## One shape, everywhere [GET /search](https://www.tinyplates.dev/docs/api/search-recipes), [GET /popular](https://www.tinyplates.dev/docs/api/popular-recipes), [GET /recipes/{id}](https://www.tinyplates.dev/docs/api/get-recipe) and [GET /recipes](https://www.tinyplates.dev/docs/api/list-recipes) all return it. Search adds a `score`, popular adds a `popularityScore`; nothing else differs. ## Reading a recipe There are two ways in, and they hold the same content. * **Structured.** `ingredients` is parsed into quantities, units, names and preparation; `instructions` is numbered steps. Use this to compute with — scaling, shopping lists, filtering. A line's `group` is the section it sits under, and `groups` lists every section in order, the ingredients' first and then the steps'. * **Flat.** `text.ingredients` and `text.instructions` are plain lines, in order, ready to render. Use this to display. An ingredient's `display` is the line to show. It is written back from the structured fields in the recipe's own language, so a Swedish recipe stays Swedish even though `name` and `ingredientId` are canonical English. That is what makes “tomat”, “Tomate” and “tomato” groupable without translating anyone's recipe. Every duration is `{ seconds }` — never “1 hr 20 mins”. Format it yourself and you can format it in any language. ## Absent means unknown An optional field that is missing means the source did not say, not that the answer is zero or false. This matters most for `dietary`: `vegan: false` is a known no, while no `vegan` key at all means nobody has established it. A flag the site declared wins; the rest are inferred from the required ingredients. The same is true of `nutrition`, whose `source` is always `provided`: the site published the figures in its structured data, retrieved when the page was crawled. The API does not compute nutrition. Its `basis` says whether the numbers are per serving, per recipe or per 100 g, so do not compare two recipes' nutrition without checking it. ## Allergen evidence `allergens` always carries the same 16 keys: the EU’s 14 regulated allergens, plus separate US definitions for wheat and tree nuts. The [GET /vocabularies](https://www.tinyplates.dev/docs/api/vocabularies) response says which jurisdictions each key belongs to. Each value is `true` when the recipe contains the allergen, counting optional lines and garnishes, and `false` when it does not. It says nothing about manufacturer cross-contact. The `disclaimer` key sits beside them. Treat this as informational, not medical advice. Keep the returned `disclaimer` wherever you show allergen results, and tell users to verify ingredients and product labels before serving someone with an allergy. ``` { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." } ``` ## Every field `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. ## A whole recipe A real response from [GET /recipes/{id}](https://www.tinyplates.dev/docs/api/get-recipe). ``` { "recipe": { "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "id": "6a9820e58f8122ec891b68a3", "author": { "name": "Lindsay Ostrom", "url": "https://pinchofyum.com/about" }, "description": "This peanut butter dark chocolate hummus is a sweet alternative to traditional hummus. Perfect served on graham crackers as an afternoon snack!", "instructions": [ { "group": "Hummus", "step": 1, "text": "Blend everything through milk in a food processor." }, { "group": "Hummus", "step": 2, "text": "Add flour by the spoonful and blend until desired consistency is reached." }, { "step": 3, "text": "Stir in dark chocolate." }, { "step": 4, "text": "Chill before serving." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=225%2C225", "variants": [ { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=195%2C195" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=180%2C180" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg" } ] } ], "notes": [ "Keeps in an airtight container in the fridge for up to five days.", "Swap the peanut butter for almond butter to make it peanut free." ], "nutrition": { "basis": { "description": "¼ cup", "servings": 8, "type": "serving" }, "calories": { "unit": "kcal", "value": 201 }, "carbohydrates": { "unit": "g", "value": 29.4 }, "cholesterol": { "unit": "mg", "value": 0.8 }, "fat": { "unit": "g", "value": 7.4 }, "fiber": { "unit": "g", "value": 3.3 }, "micronutrients": { "trans-fat": { "unit": "g", "value": 0 } }, "protein": { "unit": "g", "value": 5.6 }, "saturatedFat": { "unit": "g", "value": 2.5 }, "sodium": { "unit": "mg", "value": 76 }, "source": "provided", "sugar": { "unit": "g", "value": 16.9 } }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "max": 8, "original": "6-8", "quantity": 6 }, "times": { "cook": { "seconds": 600 }, "prep": { "seconds": 300 }, "total": { "seconds": 900 } }, "title": "Peanut Butter Dark Chocolate Hummus", "categories": [], "courses": [ "dessert" ], "createdAt": "2026-09-02T13:13:09.089Z", "cuisines": [ "american" ], "groups": [ "Hummus" ], "ingredients": [ { "display": "1 can white beans or chickpeas, rinsed", "name": "white beans or chickpeas", "optional": false, "original": "1 can white beans or chickpeas, rinsed", "preparation": "rinsed", "quantity": { "unit": "can", "value": 1 } }, { "display": "¼ cup peanut butter", "name": "peanut butter", "optional": false, "original": "¼ cup peanut butter", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "2 tbsp caramel sauce", "name": "caramel sauce", "optional": false, "original": "2 tbsp caramel sauce", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 tbsp maple syrup", "name": "maple syrup", "optional": false, "original": "2 tbsp maple syrup", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "¼ cup brown sugar", "name": "brown sugar", "optional": false, "original": "¼ cup brown sugar", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "pinch of cinnamon", "name": "pinch of cinnamon", "optional": false, "original": "pinch of cinnamon" }, { "display": "¼ cup milk", "name": "milk", "optional": false, "original": "¼ cup milk", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "¼ cup flour", "name": "flour", "optional": false, "original": "¼ cup flour", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "chopped dark chocolate", "name": "chopped dark chocolate", "optional": false, "original": "chopped dark chocolate" } ], "tags": [ "chocolate hummus", "peanut butter hummus", "peanut butter chocolate", "hummus recipe", "dessert hummus" ], "text": { "ingredients": [ "1 can white beans or chickpeas, rinsed", "¼ cup peanut butter", "2 tbsp caramel sauce", "2 tbsp maple syrup", "¼ cup brown sugar", "pinch of cinnamon", "¼ cup milk", "¼ cup flour", "chopped dark chocolate" ], "instructions": [ "Blend everything through milk in a food processor.", "Add flour by the spoonful and blend until desired consistency is reached.", "Stir in dark chocolate.", "Chill before serving." ] }, "updatedAt": "2026-09-06T01:11:59.223Z", "url": "https://pinchofyum.com/pb-dark-chocolate-hummus" } } ``` --- title: "Filtering and vocabularies — Tiny Plates recipe API" description: "Filter recipes by cuisine, course, category, diet, ingredient, language and total time, and the closed vocabularies each filter accepts." url: "https://www.tinyplates.dev/docs/filtering" --- # Filtering and vocabularies Recipes come from sites that each classify things their own way, so the pipeline maps everything onto closed lists. A filter takes a value from one of these lists — anything else is rejected with a message that says so. ## The filters All of these are optional and they combine. [GET /recipes](https://www.tinyplates.dev/docs/api/list-recipes), which needs a business plan, takes: * `cuisine, course, diet` — one value from the closed list below. * `category, ingredient` — one slug from an open set. * `ingredients, excludeIngredients` — 1 to 20 comma-separated names or ids. A recipe must carry every name in ingredients and none in excludeIngredients. * `equipment` — 1 to 20 comma-separated equipment names. A recipe must list every one of them. * `language` — a two-letter code, such as en. * `maxTotalMinutes, maxCookMinutes` — 1 to 10080 minutes, inclusive. * `time` — a preset: under-15, under-30 or weekend. * `maxCalories, maxSodium, minFiber, minProtein` — per-serving amounts: kilocalories, milligrams of sodium, grams of fiber and grams of protein. See below. * `nutrition` — one or more presets: high-fiber, high-protein, low-calorie, low-sodium. See below. * `limit, offset` — a page of 1 to 100 recipes, 20 by default, and where it starts. ``` curl 'https://api.tinyplates.dev/recipes?cuisine=italian&diet=vegetarian&maxTotalMinutes=30' \ -H 'Authorization: Bearer rd_your_api_key' ``` `diet` only returns recipes _known_ to suit it. A recipe whose flag is unknown is left out rather than guessed at, so a filtered list is safe to show to someone who actually needs it. The lists below are also served live by [GET /vocabularies](https://www.tinyplates.dev/docs/api/vocabularies), which is the version to build against — this page is a snapshot for reading. ## Nutrition Every nutrition filter is per serving and inclusive, and reads the figures the recipe was published with — nothing is recalculated.`maxCalories` takes kilocalories, `maxSodium` milligrams, and `minFiber` and `minProtein` grams. A recipe that published a nutrient in another unit is converted, not skipped. A recipe that carries no nutrition is left out, the same way an unknown diet flag is. So is one whose label was published per 100 g rather than per serving (`nutrition.basis.type` is `100g`), because turning that into a per-serving figure needs a weight the recipe does not carry. Filtering by nutrition therefore returns fewer recipes than the same filter without it. `nutrition` takes one or more presets instead of numbers. Calories and protein are the everyday reading of the words; sodium and fiber use the US FDA's labelling thresholds, which are the only widely agreed numbers. * `high-fiber` — at least 5 g of fiber per serving. * `high-protein` — at least 20 g of protein per serving. * `low-calorie` — at most 400 kcal per serving. * `low-sodium` — at most 140 mg of sodium per serving. A preset and an explicit amount for the same nutrient both apply, and the tighter of the two wins, so neither can quietly widen the other. ``` curl 'https://api.tinyplates.dev/recipes?nutrition=high-protein,low-calorie&maxSodium=500' \ -H 'Authorization: Bearer rd_your_api_key' ``` ## Cuisines * `african` * `american` * `argentinian` * `asian` * `australian` * `austrian` * `belgian` * `brazilian` * `british` * `cajun` * `caribbean` * `chinese` * `cuban` * `danish` * `dutch` * `eastern-european` * `egyptian` * `ethiopian` * `filipino` * `finnish` * `french` * `german` * `greek` * `hungarian` * `indian` * `indonesian` * `iranian` * `irish` * `israeli` * `italian` * `jamaican` * `japanese` * `korean` * `latin-american` * `lebanese` * `malaysian` * `mediterranean` * `mexican` * `middle-eastern` * `moroccan` * `norwegian` * `pakistani` * `peruvian` * `polish` * `portuguese` * `russian` * `scandinavian` * `southern-us` * `spanish` * `swedish` * `swiss` * `tex-mex` * `thai` * `turkish` * `vietnamese` ## Courses * `appetizer` * `breakfast` * `brunch` * `dessert` * `dinner` * `drink` * `lunch` * `main-course` * `side-dish` * `snack` ## Diets * `dairy-free` * `gluten-free` * `pescatarian` * `vegan` * `vegetarian` ## Allergens Every recipe feature payload assesses the EU’s 14 regulated allergens plus the distinct US definitions for wheat and tree nuts. Read them from `allergens`, keyed by identifier. To leave recipes with an allergen out, pass its identifiers as `without`, such as `without=milk,peanuts`, to [GET /recipes](https://www.tinyplates.dev/docs/api/list-recipes), [GET /search](https://www.tinyplates.dev/docs/api/search-recipes) or [GET /pantry](https://www.tinyplates.dev/docs/api/pantry-recipes). They keep only recipes that contain none of them, so a search can return fewer results than `limit`. [GET /popular](https://www.tinyplates.dev/docs/api/popular-recipes) has no allergen filter; check `allergens` on each recipe instead. Each allergen is `true` when the recipe contains it and `false` when it does not, counting optional lines and garnishes. It says nothing about manufacturer cross-contact. This data is informational, not medical advice; always verify ingredients and product labels. * `celery`(eu) * `crustaceans`(eu/us) * `eggs`(eu/us) * `fish`(eu/us) * `gluten-cereals`(eu) * `lupin`(eu) * `milk`(eu/us) * `molluscs`(eu) * `mustard`(eu) * `nuts-eu`(eu) * `peanuts`(eu/us) * `sesame`(eu/us) * `soy`(eu/us) * `sulphites`(eu) * `tree-nuts-us`(us) * `wheat`(us) ## Units Every ingredient quantity carries one of these, or none at all — a bare number is a count of pieces. Source spellings are mapped onto them, so Swedish “msk” arrives as `tbsp`. * `g` * `kg` * `lb` * `oz` * `cl` * `cup` * `dl` * `fl-oz` * `gallon` * `l` * `ml` * `pint` * `quart` * `tbsp` * `tsp` * `bag` * `bottle` * `box` * `bunch` * `can` * `clove` * `cube` * `dash` * `drop` * `ear` * `handful` * `head` * `jar` * `knob` * `leaf` * `package` * `packet` * `piece` * `pinch` * `portion` * `pot` * `scoop` * `sheet` * `shot` * `slice` * `sprig` * `stalk` * `stick` * `tub` * `cm` * `inch` ## Categories and ingredients Two filters are not closed lists. * `category` is a normalized slug from an open set — `pasta`, `soup`, `bread`. Read them off the `categories` field of recipes you already have. * `ingredient` is a canonical ingredient id such as `chicken-thigh`. [GET /ingredients](https://www.tinyplates.dev/docs/api/list-ingredients) lists them, most used first. Both must be slugs: lower-case letters, digits and single hyphens. `Main Course` is rejected; `main-course` is not. --- title: "Pagination — Tiny Plates recipe API" description: "How to page through recipe lists with limit and offset, what the pagination object in each response holds, and where the page size caps are." url: "https://www.tinyplates.dev/docs/pagination" --- # Pagination The list endpoints page with limit and offset and tell you the total, so you always know how far you have left to go. ## How it works * `limit` — how many to return. Defaults to 20 and is capped at 100\. Asking for more gives you 100, not an error. * `offset` — how many to skip. Defaults to 0. These parameters apply to [GET /popular](https://www.tinyplates.dev/docs/api/popular-recipes), [GET /pantry](https://www.tinyplates.dev/docs/api/pantry-recipes) and [GET /recipes](https://www.tinyplates.dev/docs/api/list-recipes), the last of which needs a business plan. These endpoints collapse recipes from the same publisher with matching titles, source ingredient lines, and instructions before counting or paging. Case and whitespace differences are ignored. Recipes from different publishers or with different content remain separate. The total counts these distinct results. ``` curl 'https://api.tinyplates.dev/recipes?limit=20&offset=40' \ -H 'Authorization: Bearer rd_your_api_key' ``` ## The pagination object Every paged response carries one, alongside the rows. It reflects the page you asked for and the size of the whole filtered set. `limit`integer How many recipes this response holds. Capped at 100. `offset`integer How many were skipped. `total`integer How many match the filter in total. ## Walking the whole list Stop when the offset reaches the total. Filters change the total, so read it from each response rather than assuming it. ``` const limit = 100 let offset = 0 let total = Infinity while (offset < total) { const response = await fetch( `https://api.tinyplates.dev/recipes?limit=${limit}&offset=${offset}`, { headers: { Authorization: 'Bearer rd_your_api_key' } } ) const page = await response.json() total = page.pagination.total offset += limit for (const recipe of page.recipes) { console.log(recipe.title) } } ``` At 100 a page and 50 requests a day, an account can read 5,000 recipes in a day and 30,000 in a week. See [rate limits](https://www.tinyplates.dev/docs/rate-limits). ## Search is different [GET /search](https://www.tinyplates.dev/docs/api/search-recipes) ranks results by relevance and returns only the best ones, so it has no `offset` and no `pagination` object. Its `limit` defaults to 10 and caps at 50\. If you need to page, narrow the query, or use [GET /popular](https://www.tinyplates.dev/docs/api/popular-recipes). On a business plan, [GET /recipes](https://www.tinyplates.dev/docs/api/list-recipes) pages through the whole database with filters. --- title: "Errors — Tiny Plates recipe API" description: "Every error the Tiny Plates API can return, the JSON envelope they all share, the status codes they use, and what to do about each one." url: "https://www.tinyplates.dev/docs/errors" --- # Errors Every error has the same shape and a message written to be read by a person. The status code says what kind of problem it is; the message says what to do about it. ## The envelope Whatever goes wrong, the body is the same object. There is no error code to switch on — branch on the HTTP status, and show the message. ``` { "error": { "message": "Recipe not found." } } ``` An unmatched path answers `404` with the same envelope: `No such endpoint. See /docs for the available routes.` ## Bad requests A parameter the API cannot use is rejected rather than ignored, so a typo shows up as an error instead of an empty page. The message names the parameter, the value it was given, and where the allowed values are listed. * 400 The query parameter is required. The \`query\` parameter was missing or empty. * 400 Unknown cuisine "italien". The allowed values are listed by GET /vocabularies. A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "limit" parameter must be a whole number of at least 1; got "many". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "language" parameter must be a two-letter code such as "en" or "sv"; got "english". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "category" parameter must be a slug such as "main-course" or "chicken-thigh"; got "Main Course". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. The closed vocabularies are on [filtering and vocabularies](https://www.tinyplates.dev/docs/filtering), and served live by [GET /vocabularies](https://www.tinyplates.dev/docs/api/vocabularies). ## Keys * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. See [authentication](https://www.tinyplates.dev/docs/authentication) for how a key is sent, and [rate limits](https://www.tinyplates.dev/docs/rate-limits) for the 429. ## Missing things * 404 Recipe not found. No recipe has that id. Ids are opaque strings from a list or search response, not slugs. ## Our fault * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. A 500 is never caused by the request. Retrying is reasonable — once, after a short pause. If it keeps happening, the request was fine and we want to hear about it. --- title: "Rate limits — Tiny Plates recipe API" description: "How requests count against each plan's daily and weekly limits, what a 429 looks like, when it resets and how to stay under." url: "https://www.tinyplates.dev/docs/rate-limits" --- # Rate limits Every account's requests count against its plan's limits, across all of its keys. See the [plans](https://www.tinyplates.dev/pricing) for what each one includes. ## The limits | Plan | Daily limit | Weekly limit | | ---------- | ----------- | ------------ | | Free | 50 | 300 | | Personal | 5,000 | No limit | | Business | 20,000 | No limit | | Enterprise | Custom | Custom | * The day resets at midnight UTC, not 24 hours after your first request. * The week is rolling: today and the previous six UTC days. Room comes back as older days drop out of the window. * Every request that carries a key counts, including ones that answer with an error. Your [dashboard](https://www.tinyplates.dev/dashboard/usage) shows what you have used, and what each key has used per day and per endpoint. ## Going over Once a limit is spent, every call from the account answers `429` until the window moves. On Free the message says which allowance ran out and points at the plans: ``` { "error": { "message": "Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing." } } ``` ``` { "error": { "message": "Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing." } } ``` Paid plans get a message that names the plan and the limit: ``` { "error": { "message": "Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit." } } ``` There is no `Retry-After` header yet. The daily limit is back at midnight UTC; the weekly one frees up as days drop out of the window. Until then, back off rather than retrying immediately. ## Staying under * Cache what does not change. `/vocabularies` changes rarely; fetch it once at start-up, not per request. * Ask for less. `limit` and the `fields` parameter on [search](https://www.tinyplates.dev/docs/api/search-recipes) both cut the work. * Use a key per application. It will not raise the ceiling, but the dashboard then tells you which one is spending it. * Need more? See the plans on the [pricing page](https://www.tinyplates.dev/pricing), or [contact us](https://www.tinyplates.dev/contact) for Enterprise. --- title: "Search recipes — Tiny Plates recipe API" description: "Search recipes by meaning as well as wording, across names, ingredients and descriptions, and return only the fields you need." url: "https://www.tinyplates.dev/docs/api/search-recipes" --- # Search recipes Search recipes by meaning as well as wording, across names, ingredients and descriptions, and return only the fields you need. GET`/search`API key Searches names, ingredients and descriptions. Matching is on meaning as well as wording, so "creamy pasta" also finds carbonara. Results carry a \`score\` that is only meaningful relative to the others in the same response — do not read it as an absolute rating. ## Request ``` curl 'https://api.tinyplates.dev/search?query=creamy+pasta&limit=3' \ -H 'Authorization: Bearer rd_your_api_key' ``` query\* fields language limit without Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `query`stringrequired What to search for. * `fields`string A comma-separated list of recipe fields to return. \`id\` and \`score\` are always included. Use it to keep responses small when you only need a few fields. * `language`stringdefaults to `en` Only return recipes written in this language, as a two-letter ISO 639-1 code. * `limit`integerdefaults to `10`1–50 How many results to return. Unlike the list endpoints this one caps at 50, and a value that is not a whole number is ignored rather than rejected. * `without`string Leave out recipes that contain any listed allergen feature (comma-separated ids from /vocabularies). Only recipes whose \`allergens\` value is \`false\` for every listed feature are returned, so a search can return fewer than \`limit\` results. Informational, not medical advice. An unknown feature returns 400. ## Response `results[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. `score`number A rank fusion of the meaning and the wording legs of the search, plus a bonus for a title that contains the query. Higher comes first. It is a rank, not a confidence: scores are comparable only within one response. The matching recipes, best first. When \`fields\` is set, only the requested fields plus \`id\` and \`score\` are present. Example ``` { "results": [ { "id": "6a980d75ea7517554c2894b1", "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "createdAt": "2026-09-02T11:50:13.886Z", "dietary": { "glutenFree": true, "vegetarian": true }, "instructions": [ { "equipment": [ "oven" ], "step": 1, "temperature": { "unit": "F", "value": 325 }, "text": "Preheat oven to 325°." }, { "ingredients": [ "roma-tomato" ], "step": 2, "techniques": [ "slicing" ], "text": "Slice tomatoes in half." }, { "ingredients": [ "salt", "basil", "oregano", "thyme" ], "step": 3, "techniques": [ "seasoning" ], "text": "Season with salt, basil, oregano and thyme." }, { "equipment": [ "baking-sheet" ], "ingredients": [ "olive-oil", "roma-tomato" ], "step": 4, "techniques": [ "spraying" ], "text": "Spray a cookie sheet with olive oil spray and place tomatoes cut side up." }, { "duration": { "seconds": 7200 }, "equipment": [ "oven" ], "ingredients": [ "roma-tomato" ], "step": 5, "techniques": [ "baking" ], "text": "Bake 2 hrs until skin gets wrinkled and crusty on the bottom and moist in the center." }, { "equipment": [ "food-processor" ], "ingredients": [ "roma-tomato" ], "step": 6, "techniques": [ "pureeing" ], "text": "Puree the tomatoes in a food processor." }, { "step": 7, "text": "If it is too thick, you can thin with pasta water." }, { "ingredients": [ "roma-tomato" ], "step": 8, "text": "Serve over your favorite high fiber pasta and grated cheese." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://www.skinnytaste.com/wp-content/uploads/2008/08/roasted-tomatoe-sauce.jpg", "variants": [ { "url": "https://www.skinnytaste.com/wp-content/uploads/2008/08/roasted-tomatoe-sauce-425x270.jpg" } ] } ], "nutrition": { "basis": { "type": "serving" }, "calories": { "unit": "kcal", "value": 78.1 }, "carbohydrates": { "unit": "g", "value": 17.3 }, "fat": { "unit": "g", "value": 1.2 }, "fiber": { "unit": "g", "value": 4.1 }, "protein": { "unit": "g", "value": 3.2 }, "source": "provided" }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "original": "4 servings", "quantity": 4 }, "times": {}, "title": "Candied Tomato Sauce", "updatedAt": "2026-09-06T01:39:14.527Z", "categories": [], "courses": [], "cuisines": [ "italian" ], "groups": [], "ingredients": [ { "display": "12 ripe Roma tomatoes", "localName": "Roma tomatoes", "ingredientId": "roma-tomato", "name": "Roma tomato", "optional": false, "original": "12 ripe Roma tomatoes", "quantity": { "value": 12 }, "size": "ripe" }, { "display": "salt", "localName": "salt", "ingredientId": "salt", "name": "salt", "note": "to taste", "optional": false, "original": "salt to taste" }, { "display": "1 tsp thyme", "localName": "thyme", "ingredientId": "thyme", "name": "thyme", "optional": false, "original": "1 tsp thyme", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "1 tsp oregano", "localName": "oregano", "ingredientId": "oregano", "name": "oregano", "optional": false, "original": "1 tsp oregano", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "olive oil spray", "localName": "olive oil", "ingredientId": "olive-oil", "name": "olive oil", "optional": false, "original": "olive oil spray", "preparation": "spray" }, { "display": "2 tbsp basil, chopped", "localName": "basil", "ingredientId": "basil", "name": "basil", "optional": false, "original": "2 tbsp basil, chopped", "preparation": "chopped", "quantity": { "unit": "tbsp", "value": 2 } } ], "tags": [ "freezer meals", "gluten free", "vegetarian meals" ], "text": { "ingredients": [ "12 ripe Roma tomatoes", "salt", "1 tsp thyme", "1 tsp oregano", "olive oil spray", "2 tbsp basil, chopped" ], "instructions": [ "Preheat oven to 325°.", "Slice tomatoes in half.", "Season with salt, basil, oregano and thyme.", "Spray a cookie sheet with olive oil spray and place tomatoes cut side up.", "Bake 2 hrs until skin gets wrinkled and crusty on the bottom and moist in the center.", "Puree the tomatoes in a food processor.", "If it is too thick, you can thin with pasta water.", "Serve over your favorite high fiber pasta and grated cheese." ] }, "url": "https://www.skinnytaste.com/candied-tomato-sauce-0-ww-pts/", "equipment": [ "baking sheet", "food processor", "oven" ], "techniques": [ "baking", "pureeing", "seasoning", "slicing", "spraying" ], "score": 0.0333 } ] } ``` ## Errors * 400 The query parameter is required. The \`query\` parameter was missing or empty. * 400 The "without" parameter must be a comma-separated list of allergen features from GET /vocabularies, such as "milk,peanuts"; got "dairy". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [The recipe object](https://www.tinyplates.dev/docs/recipe-object) * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) --- title: "Popular recipes — Tiny Plates recipe API" description: "The best-loved recipes in the database, ranked by rating and by how many people rated them, so one five-star review cannot beat a long-loved favourite." url: "https://www.tinyplates.dev/docs/api/popular-recipes" --- # Popular recipes The best-loved recipes in the database, ranked by rating and by how many people rated them, so one five-star review cannot beat a long-loved favourite. GET`/popular`API key Returns the most popular recipes first. Ranking favours recipes that are both well rated and rated by a lot of people, so a single five-star review does not outrank a long-standing favourite. ## Request ``` curl 'https://api.tinyplates.dev/popular?limit=3' \ -H 'Authorization: Bearer rd_your_api_key' ``` language limit offset Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `language`stringdefaults to `en` Only return recipes written in this language, as a two-letter ISO 639-1 code. * `limit`integerdefaults to `20`at least 1 How many recipes to return. * `offset`integerdefaults to `0`at least 0 How many recipes to skip. Use it with \`limit\` to page. ## Response `pagination`object `limit`integer How many recipes this response holds. Capped at 100. `offset`integer How many were skipped. `total`integer How many match the filter in total. Offset pagination. `recipes[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. `popularityScore`number How popular this recipe is relative to the others in this response. Higher comes first. The recipes, most popular first. Example ``` { "pagination": { "limit": 1, "offset": 0, "total": 1848 }, "recipes": [ { "id": "6a9820a88f8122ec891b680b", "description": "No canning, no fuss—just crisp, tangy pickles you’ll want to eat with everything!", "instructions": [ { "step": 1, "text": "Combine the vinegar, salt and sugar in a small non-reactive saucepan (such as stainless steel, glass, ceramic or teflon) over high heat. Whisk until the salt and sugar are dissolved. Transfer the liquid into a bowl and whisk in the cold water. Refrigerate brine until ready to use." }, { "step": 2, "text": "Stuff the cucumbers into two clean 1 qt (1L) jars. Add the coriander seeds, garlic cloves, mustard seeds, red pepper flakes, dill sprigs, and chilled brine into jars, dividing evenly. If necessary, add a bit of cold water to the jars until the brine covers the cucumbers. Cover and refrigerate about 24 hours, then serve. The pickles will keep in the refrigerator for up to one month." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://www.onceuponachef.com/images/2012/04/pickles.jpg", "variants": [ { "url": "https://www.onceuponachef.com/images/2012/04/pickles-500x500.jpg" }, { "url": "https://www.onceuponachef.com/images/2012/04/pickles-500x375.jpg" }, { "url": "https://www.onceuponachef.com/images/2012/04/pickles-480x270.jpg" } ] } ], "rating": { "count": 517, "reviewCount": 11, "value": 4.93 }, "servings": { "original": "2 (1-qt) jars (about 24 spears)", "quantity": 2 }, "times": { "cook": { "seconds": 300 }, "prep": { "seconds": 900 }, "total": { "seconds": 1200 } }, "title": "Quick & Easy Refrigerator Pickles", "categories": [], "courses": [ "snack" ], "createdAt": "2026-09-02T13:12:08.379Z", "cuisines": [ "american" ], "groups": [], "ingredients": [ { "display": "1¼ cup distilled white vinegar (5% acidity)", "name": "distilled white vinegar", "note": "5% acidity", "optional": false, "original": "1¼ cup distilled white vinegar (5% acidity)", "quantity": { "unit": "cup", "value": 1.25 } }, { "display": "3 tbsp kosher salt", "name": "kosher salt", "optional": false, "original": "3 tbsp kosher salt", "quantity": { "unit": "tbsp", "value": 3 } }, { "display": "2 tbsp sugar", "name": "sugar", "optional": false, "original": "2 tbsp sugar", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 cup cold water", "name": "cold water", "optional": false, "original": "2 cup cold water", "quantity": { "unit": "cup", "value": 2 } }, { "display": "1¾-2 lb Kirby cucumbers, cut into halves or spears (about 6)", "name": "Kirby cucumbers", "note": "about 6", "optional": false, "original": "1¾-2 lb Kirby cucumbers, cut into halves or spears (about 6)", "preparation": "cut into halves or spears", "quantity": { "max": 2, "unit": "lb", "value": 1.75 } }, { "display": "2 tbsp coriander seeds", "name": "coriander seeds", "optional": false, "original": "2 tbsp coriander seeds", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "6 large garlic cloves (peeled and halved)", "name": "garlic cloves", "note": "peeled and halved", "optional": false, "original": "6 large garlic cloves (peeled and halved)", "quantity": { "value": 6 }, "size": "large" }, { "display": "1 tsp mustard seeds", "name": "mustard seeds", "optional": false, "original": "1 tsp mustard seeds", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "¼ tsp crushed red pepper flakes", "name": "crushed red pepper flakes", "optional": false, "original": "¼ tsp crushed red pepper flakes", "quantity": { "unit": "tsp", "value": 0.25 } }, { "display": "16 dill sprigs", "name": "dill sprigs", "optional": false, "original": "16 dill sprigs", "quantity": { "value": 16 } } ], "tags": [ "pickles" ], "text": { "ingredients": [ "1¼ cup distilled white vinegar (5% acidity)", "3 tbsp kosher salt", "2 tbsp sugar", "2 cup cold water", "1¾-2 lb Kirby cucumbers, cut into halves or spears (about 6)", "2 tbsp coriander seeds", "6 large garlic cloves (peeled and halved)", "1 tsp mustard seeds", "¼ tsp crushed red pepper flakes", "16 dill sprigs" ], "instructions": [ "Combine the vinegar, salt and sugar in a small non-reactive saucepan (such as stainless steel, glass, ceramic or teflon) over high heat. Whisk until the salt and sugar are dissolved. Transfer the liquid into a bowl and whisk in the cold water. Refrigerate brine until ready to use.", "Stuff the cucumbers into two clean 1 qt (1L) jars. Add the coriander seeds, garlic cloves, mustard seeds, red pepper flakes, dill sprigs, and chilled brine into jars, dividing evenly. If necessary, add a bit of cold water to the jars until the brine covers the cucumbers. Cover and refrigerate about 24 hours, then serve. The pickles will keep in the refrigerator for up to one month." ] }, "updatedAt": "2026-09-06T01:11:59.030Z", "url": "https://www.onceuponachef.com/recipes/quick-and-easy-dill-pickles.html", "popularityScore": 4.89536312849162 } ] } ``` ## Errors * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [The recipe object](https://www.tinyplates.dev/docs/recipe-object) * [Pagination](https://www.tinyplates.dev/docs/pagination) * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Recipes * [Get a recipe](https://www.tinyplates.dev/docs/api/get-recipe) * [Cook from your pantry](https://www.tinyplates.dev/docs/api/pantry-recipes) * [Build a shopping list](https://www.tinyplates.dev/docs/api/shopping-list) * [List recipes](https://www.tinyplates.dev/docs/api/list-recipes) --- title: "Get a recipe — Tiny Plates recipe API" description: "Fetch a single recipe by its id, with structured ingredients, numbered steps, times, nutrition and media, scaled to the number of servings you ask for." url: "https://www.tinyplates.dev/docs/api/get-recipe" --- # Get a recipe Fetch a single recipe by its id, with structured ingredients, numbered steps, times, nutrition and media, scaled to the number of servings you ask for. GET`/recipes/{id}`API key Returns one recipe in full. The id is the opaque string a list or search response carries in its \`id\` field; it is not a slug and not the source URL. \`servings\` rewrites the recipe for a different number of servings. ## Request ``` curl 'https://api.tinyplates.dev/recipes/6a9820e58f8122ec891b68a3' \ -H 'Authorization: Bearer rd_your_api_key' ``` id\* servings units Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `id`stringrequired The recipe id, from a list or search response. * `servings`integer1–100 Rewrite every quantity for this many servings (1–100). Ranges scale with them; an ingredient with no quantity, such as "salt to taste", is left alone; \`original\` still holds the line the source published. Per-serving nutrition does not change. A recipe that does not say what it makes returns 400. * `units`string Rewrite the recipe in "metric" or "imperial" units. Mass and volume are converted, oven temperatures with them, and a volume becomes a weight when a density is known for the ingredient. A volume it cannot weigh keeps the unit the source wrote it in, and so do spoons, counts such as cloves, and units already in the target system. Every amount is then written the way a cook would read it, which can change the unit within a system: "0.5 l" becomes "500 ml" and "1500 g" becomes "1.5 kg". Anything unknown returns 400. ## Response `conversion`objectoptional `system`string The system the recipe was rewritten in. `unweighed`string\[\] Ingredients measured by volume that could not be weighed, because no density is known for them. Their lines keep the unit the source wrote them in. What the unit conversion did. Present only when \`units\` was given. `nutritionTotals`objectoptional `basisServings`number The serving count perRecipe was multiplied up from: the label's own basis when the recipe declares one — a recipe stored as serving 8 to 10 can carry a label worked out on 10, not the stored 8 — otherwise the serving count the recipe had before any scaling. `perRecipe`object Nutrition for the whole recipe. `perServing`object Nutrition for one serving. `servings`number The serving count both figures were worked out from. The same nutrition told twice: for one serving, which is what recipes are compared on, and for the whole recipe, which is what the cook is making. Present only when the recipe carries nutrition and says how many servings it makes; figures published per 100 g cannot be split this way and are left out. Scaling with \`servings\` changes the whole-recipe figures and leaves the per-serving ones alone. `recipe`object `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. The recipe. Example ``` { "recipe": { "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "id": "6a9820e58f8122ec891b68a3", "author": { "name": "Lindsay Ostrom", "url": "https://pinchofyum.com/about" }, "description": "This peanut butter dark chocolate hummus is a sweet alternative to traditional hummus. Perfect served on graham crackers as an afternoon snack!", "instructions": [ { "group": "Hummus", "step": 1, "text": "Blend everything through milk in a food processor." }, { "group": "Hummus", "step": 2, "text": "Add flour by the spoonful and blend until desired consistency is reached." }, { "step": 3, "text": "Stir in dark chocolate." }, { "step": 4, "text": "Chill before serving." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=225%2C225", "variants": [ { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=195%2C195" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=180%2C180" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg" } ] } ], "notes": [ "Keeps in an airtight container in the fridge for up to five days.", "Swap the peanut butter for almond butter to make it peanut free." ], "nutrition": { "basis": { "description": "¼ cup", "servings": 8, "type": "serving" }, "calories": { "unit": "kcal", "value": 201 }, "carbohydrates": { "unit": "g", "value": 29.4 }, "cholesterol": { "unit": "mg", "value": 0.8 }, "fat": { "unit": "g", "value": 7.4 }, "fiber": { "unit": "g", "value": 3.3 }, "micronutrients": { "trans-fat": { "unit": "g", "value": 0 } }, "protein": { "unit": "g", "value": 5.6 }, "saturatedFat": { "unit": "g", "value": 2.5 }, "sodium": { "unit": "mg", "value": 76 }, "source": "provided", "sugar": { "unit": "g", "value": 16.9 } }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "max": 8, "original": "6-8", "quantity": 6 }, "times": { "cook": { "seconds": 600 }, "prep": { "seconds": 300 }, "total": { "seconds": 900 } }, "title": "Peanut Butter Dark Chocolate Hummus", "categories": [], "courses": [ "dessert" ], "createdAt": "2026-09-02T13:13:09.089Z", "cuisines": [ "american" ], "groups": [ "Hummus" ], "ingredients": [ { "display": "1 can white beans or chickpeas, rinsed", "name": "white beans or chickpeas", "optional": false, "original": "1 can white beans or chickpeas, rinsed", "preparation": "rinsed", "quantity": { "unit": "can", "value": 1 } }, { "display": "¼ cup peanut butter", "name": "peanut butter", "optional": false, "original": "¼ cup peanut butter", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "2 tbsp caramel sauce", "name": "caramel sauce", "optional": false, "original": "2 tbsp caramel sauce", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 tbsp maple syrup", "name": "maple syrup", "optional": false, "original": "2 tbsp maple syrup", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "¼ cup brown sugar", "name": "brown sugar", "optional": false, "original": "¼ cup brown sugar", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "pinch of cinnamon", "name": "pinch of cinnamon", "optional": false, "original": "pinch of cinnamon" }, { "display": "¼ cup milk", "name": "milk", "optional": false, "original": "¼ cup milk", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "¼ cup flour", "name": "flour", "optional": false, "original": "¼ cup flour", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "chopped dark chocolate", "name": "chopped dark chocolate", "optional": false, "original": "chopped dark chocolate" } ], "tags": [ "chocolate hummus", "peanut butter hummus", "peanut butter chocolate", "hummus recipe", "dessert hummus" ], "text": { "ingredients": [ "1 can white beans or chickpeas, rinsed", "¼ cup peanut butter", "2 tbsp caramel sauce", "2 tbsp maple syrup", "¼ cup brown sugar", "pinch of cinnamon", "¼ cup milk", "¼ cup flour", "chopped dark chocolate" ], "instructions": [ "Blend everything through milk in a food processor.", "Add flour by the spoonful and blend until desired consistency is reached.", "Stir in dark chocolate.", "Chill before serving." ] }, "updatedAt": "2026-09-06T01:11:59.223Z", "url": "https://pinchofyum.com/pb-dark-chocolate-hummus" } } ``` ## Errors * 404 Recipe not found. No recipe has that id. Ids are opaque strings from a list or search response, not slugs. * 400 The "servings" parameter must be a whole number between 1 and 100; got "0". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 This recipe does not say how many servings it makes, so it cannot be scaled. Request it without the "servings" parameter. A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "units" parameter must be "metric" or "imperial"; got "stones". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [The recipe object](https://www.tinyplates.dev/docs/recipe-object) * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Recipes * [Popular recipes](https://www.tinyplates.dev/docs/api/popular-recipes) * [Cook from your pantry](https://www.tinyplates.dev/docs/api/pantry-recipes) * [Build a shopping list](https://www.tinyplates.dev/docs/api/shopping-list) * [List recipes](https://www.tinyplates.dev/docs/api/list-recipes) --- title: "Cook from your pantry — Tiny Plates recipe API" description: "Rank recipes by how much of them your pantry already covers, with the missing ingredients listed, so you can see what you can cook right now." url: "https://www.tinyplates.dev/docs/api/pantry-recipes" --- # Cook from your pantry Rank recipes by how much of them your pantry already covers, with the missing ingredients listed, so you can see what you can cook right now. GET`/pantry`API key Returns what you can cook from what you have, best covered first. \`ingredients\` is the pantry. Only recipes using at least one pantry ingredient are returned; each carries the ingredients your pantry covers and the ones it does not, named as the recipe names them. Salt, pepper, water, oil, sugar and flour are taken as already in the kitchen: they come back in \`assumedIngredients\` and count neither towards the coverage nor as missing, because nobody shops for salt. Send \`staples=false\` to count them as ingredients you need. \`maxMissing\` narrows the results to recipes you are short no more than that many ingredients for, so \`maxMissing=0\` is what you can cook right now. Matching is the same as the \`ingredients\` filter of GET /recipes: exact canonical ids or whole canonical names, with a space and a hyphen treated alike. ## Request ``` curl 'https://api.tinyplates.dev/pantry?ingredients=chicken%2Crice%2Conion&limit=3' \ -H 'Authorization: Bearer rd_your_api_key' ``` ingredients\* language limit maxMissing offset staples without Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `ingredients`stringrequired The ingredients you have: 1 to 20 comma-separated names or canonical ids, each at most 80 characters. Required. * `language`stringdefaults to `en` Only return recipes written in this language, as a two-letter ISO 639-1 code. * `limit`integerdefaults to `20`at least 1 How many recipes to return. * `maxMissing`integer0–20 Only return recipes you are missing at most this many ingredients for (0–20). 0 returns what you can cook right now. Left out, a recipe may be missing any number. * `offset`integerdefaults to `0`at least 0 How many recipes to skip. Use it with \`limit\` to page. * `staples`string Whether the staples a kitchen is assumed to have — salt, sea salt, kosher salt, pepper, black pepper, water, oil, olive oil, vegetable oil, sugar, flour, all-purpose flour — count as on hand. "false" counts them as ingredients you need. Defaults to "true". * `without`string Leave out recipes that contain any listed allergen feature (comma-separated ids from /vocabularies). Only recipes whose \`allergens\` value is \`false\` for every listed feature are returned, and \`pagination.total\` counts only those. Informational, not medical advice. An unknown feature returns 400. ## Response `pagination`object `limit`integer How many recipes this response holds. Capped at 100. `offset`integer How many were skipped. `total`integer How many match the filter in total. Offset pagination. `recipes[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. `assumedIngredients`string\[\] The staples the recipe uses, taken as already in your kitchen. Empty when "staples=false". `coverage`number The share of the recipe's ingredients your pantry covers, from 0 to 1, rounded to two decimals. Staples are in neither half of it. `matchedIngredients`string\[\] The recipe ingredients your pantry covers. `missingIngredients`string\[\] The recipe ingredients your pantry does not cover. The recipes, best covered first. Example ``` { "pagination": { "limit": 1, "offset": 0, "total": 112 }, "recipes": [ { "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "id": "6a9820e58f8122ec891b68a3", "author": { "name": "Lindsay Ostrom", "url": "https://pinchofyum.com/about" }, "description": "This peanut butter dark chocolate hummus is a sweet alternative to traditional hummus. Perfect served on graham crackers as an afternoon snack!", "instructions": [ { "group": "Hummus", "step": 1, "text": "Blend everything through milk in a food processor." }, { "group": "Hummus", "step": 2, "text": "Add flour by the spoonful and blend until desired consistency is reached." }, { "step": 3, "text": "Stir in dark chocolate." }, { "step": 4, "text": "Chill before serving." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=225%2C225", "variants": [ { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=195%2C195" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=180%2C180" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg" } ] } ], "notes": [ "Keeps in an airtight container in the fridge for up to five days.", "Swap the peanut butter for almond butter to make it peanut free." ], "nutrition": { "basis": { "description": "¼ cup", "servings": 8, "type": "serving" }, "calories": { "unit": "kcal", "value": 201 }, "carbohydrates": { "unit": "g", "value": 29.4 }, "cholesterol": { "unit": "mg", "value": 0.8 }, "fat": { "unit": "g", "value": 7.4 }, "fiber": { "unit": "g", "value": 3.3 }, "micronutrients": { "trans-fat": { "unit": "g", "value": 0 } }, "protein": { "unit": "g", "value": 5.6 }, "saturatedFat": { "unit": "g", "value": 2.5 }, "sodium": { "unit": "mg", "value": 76 }, "source": "provided", "sugar": { "unit": "g", "value": 16.9 } }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "max": 8, "original": "6-8", "quantity": 6 }, "times": { "cook": { "seconds": 600 }, "prep": { "seconds": 300 }, "total": { "seconds": 900 } }, "title": "Peanut Butter Dark Chocolate Hummus", "categories": [], "courses": [ "dessert" ], "createdAt": "2026-09-02T13:13:09.089Z", "cuisines": [ "american" ], "groups": [ "Hummus" ], "ingredients": [ { "display": "1 can white beans or chickpeas, rinsed", "name": "white beans or chickpeas", "optional": false, "original": "1 can white beans or chickpeas, rinsed", "preparation": "rinsed", "quantity": { "unit": "can", "value": 1 } }, { "display": "¼ cup peanut butter", "name": "peanut butter", "optional": false, "original": "¼ cup peanut butter", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "2 tbsp caramel sauce", "name": "caramel sauce", "optional": false, "original": "2 tbsp caramel sauce", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 tbsp maple syrup", "name": "maple syrup", "optional": false, "original": "2 tbsp maple syrup", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "¼ cup brown sugar", "name": "brown sugar", "optional": false, "original": "¼ cup brown sugar", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "pinch of cinnamon", "name": "pinch of cinnamon", "optional": false, "original": "pinch of cinnamon" }, { "display": "¼ cup milk", "name": "milk", "optional": false, "original": "¼ cup milk", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "¼ cup flour", "name": "flour", "optional": false, "original": "¼ cup flour", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "chopped dark chocolate", "name": "chopped dark chocolate", "optional": false, "original": "chopped dark chocolate" } ], "tags": [ "chocolate hummus", "peanut butter hummus", "peanut butter chocolate", "hummus recipe", "dessert hummus" ], "text": { "ingredients": [ "1 can white beans or chickpeas, rinsed", "¼ cup peanut butter", "2 tbsp caramel sauce", "2 tbsp maple syrup", "¼ cup brown sugar", "pinch of cinnamon", "¼ cup milk", "¼ cup flour", "chopped dark chocolate" ], "instructions": [ "Blend everything through milk in a food processor.", "Add flour by the spoonful and blend until desired consistency is reached.", "Stir in dark chocolate.", "Chill before serving." ] }, "updatedAt": "2026-09-06T01:11:59.223Z", "url": "https://pinchofyum.com/pb-dark-chocolate-hummus", "assumedIngredients": [ "flour" ], "coverage": 0.75, "matchedIngredients": [ "white beans or chickpeas", "peanut butter", "maple syrup", "brown sugar", "pinch of cinnamon", "milk" ], "missingIngredients": [ "caramel sauce", "chopped dark chocolate" ] } ] } ``` ## Errors * 400 The "ingredients" parameter is required. Send the ingredients you have, such as "chicken,rice". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "maxMissing" parameter must be a whole number between 0 and 20\. Send how many ingredients you are willing to shop for, such as 1. A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "staples" parameter must be "true" or "false"; got "no". Send "staples=false" to count salt, pepper, oil and the rest as ingredients you need. A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "without" parameter must be a comma-separated list of allergen features from GET /vocabularies, such as "milk,peanuts"; got "dairy". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [The recipe object](https://www.tinyplates.dev/docs/recipe-object) * [Pagination](https://www.tinyplates.dev/docs/pagination) * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Recipes * [Popular recipes](https://www.tinyplates.dev/docs/api/popular-recipes) * [Get a recipe](https://www.tinyplates.dev/docs/api/get-recipe) * [Build a shopping list](https://www.tinyplates.dev/docs/api/shopping-list) * [List recipes](https://www.tinyplates.dev/docs/api/list-recipes) --- title: "Build a shopping list — Tiny Plates recipe API" description: "Turn several recipes and their serving counts into one shopping list, grouped by aisle, with the amounts of shared ingredients added together." url: "https://www.tinyplates.dev/docs/api/shopping-list" --- # Build a shopping list Turn several recipes and their serving counts into one shopping list, grouped by aisle, with the amounts of shared ingredients added together. GET`/shopping-list`API key Consolidates several recipes into one shopping list, grouped by the aisle each ingredient is found in. \`recipes\` is a comma-separated list of recipe ids, each optionally followed by a colon and the servings to cook. A recipe asked for at a different serving count is scaled first, so the list holds the amounts actually needed. Quantities are added up wherever they can be — grams to grams, cloves to cloves — and amounts that cannot be added, such as two cloves of garlic and 10 g of garlic, stay separate lines. An amount an ingredient note adds, such as "plus 3 tbsp", is added to the line in the same unit and kept beside it in \`extras\` in any other. An ingredient with no quantity, such as "salt to taste", is one line with no amount. Every total is written the way a cook would read it: "1.5 kg", not "1500 g", and "2¾ tbsp", not "0.17 cup". ## Request ``` curl 'https://api.tinyplates.dev/shopping-list?recipes=6a9820a88f8122ec891b680b%3A6%2C6a9820e58f8122ec891b68a4' \ -H 'Authorization: Bearer rd_your_api_key' ``` recipes\* Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `recipes`stringrequired The recipes to shop for: 1 to 20 comma-separated recipe ids, each optionally followed by ":" and the servings to cook. Required. ## Response `items[]`object\[\] `category`string The aisle: bakery, dairy, drinks, frozen, meat, other, pantry, produce, seafood or spices. `display`string The line as a reader would write it. `extras`object\[\]optional Amounts a recipe asked for in a unit the quantity cannot take, one per unit, such as the 3 tbsp in "1 cup + 3 tbsp". Buy them as well as the quantity. `name`string The ingredient name. `plusMore`booleanoptional Present when a recipe also asked for this without saying how much — oil for frying, a garnish — so the quantity is a minimum rather than the whole of it. `quantity`objectoptional The amount to buy. Absent when no recipe gave one, such as "salt to taste". `recipeIds`string\[\] The ids of the recipes that asked for it. The list, grouped by aisle and then by name. `recipes[]`object\[\] `id`string The recipe id. `servings`number The servings the recipe was scaled to. `title`string The recipe title. The recipes the list was built from, in the order they were asked for, with the servings each was scaled to. Example ``` { "items": [ { "category": "dairy", "display": "250 ml double cream", "name": "double cream", "quantity": { "unit": "ml", "value": 250 }, "recipeIds": [ "6a9820a88f8122ec891b680b" ] }, { "category": "dairy", "display": "1 cup + 3 tbsp pecorino romano", "extras": [ { "unit": "tbsp", "value": 3 } ], "name": "pecorino romano", "quantity": { "unit": "cup", "value": 1 }, "recipeIds": [ "6a9820e58f8122ec891b68a4" ] }, { "category": "meat", "display": "1.2 kg chicken thighs", "name": "chicken thighs", "quantity": { "unit": "kg", "value": 1.2 }, "recipeIds": [ "6a9820a88f8122ec891b680b", "6a9820e58f8122ec891b68a4" ] }, { "category": "produce", "display": "5 onion", "name": "onion", "quantity": { "value": 5 }, "recipeIds": [ "6a9820a88f8122ec891b680b", "6a9820e58f8122ec891b68a4" ] }, { "category": "spices", "display": "salt", "name": "salt", "recipeIds": [ "6a9820e58f8122ec891b68a4" ] } ], "recipes": [ { "id": "6a9820a88f8122ec891b680b", "servings": 6, "title": "Chicken Tikka Masala" }, { "id": "6a9820e58f8122ec891b68a4", "servings": 4, "title": "Slow-Roasted Cherry Tomatoes" } ] } ``` ## Errors * 400 The "recipes" parameter must contain 1 to 20 recipe ids, each optionally followed by ":" and a serving count. Use "66d0a1b2c3d4e5f6a7b8c9d0:6,66d0a1b2c3d4e5f6a7b8c9d1". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 No recipe with id "66d0a1b2c3d4e5f6a7b8c9ff". Use the ids a list or search response carries in its "id" field. A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [The recipe object](https://www.tinyplates.dev/docs/recipe-object) * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Recipes * [Popular recipes](https://www.tinyplates.dev/docs/api/popular-recipes) * [Get a recipe](https://www.tinyplates.dev/docs/api/get-recipe) * [Cook from your pantry](https://www.tinyplates.dev/docs/api/pantry-recipes) * [List recipes](https://www.tinyplates.dev/docs/api/list-recipes) --- title: "List recipes — Tiny Plates recipe API" description: "Business plan only. Page through the whole database, newest first, filtered by cuisine, course, category, diet, ingredient, language or total time." url: "https://www.tinyplates.dev/docs/api/list-recipes" --- # List recipes Business plan only. Page through the whole database, newest first, filtered by cuisine, course, category, diet, ingredient, language or total time. GET`/recipes`API keyBusiness plan Requires a business plan. Returns recipes newest first. Every filter is optional and they combine, so \`?cuisine=italian&diet=vegetarian&maxTotalMinutes=30\` is a valid request. Values for \`course\`, \`cuisine\` and \`diet\` come from the closed vocabularies; \`category\` and \`ingredient\` take a slug. Equipment matching uses the structured equipment field; recipes with unknown equipment do not match. ## Request ``` curl 'https://api.tinyplates.dev/recipes?limit=3' \ -H 'Authorization: Bearer rd_your_api_key' ``` category course cuisine diet ingredient maxCookMinutes maxCalories minProtein maxSodium minFiber nutrition time equipment ingredients language excludeIngredients limit maxTotalMinutes offset without Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `category`slug A normalized category slug, such as "pasta" or "soup". Categories come from an open set — read them off the \`categories\` field of a recipe. * `course`slug A course from the closed list. 10 allowed values `appetizer` `breakfast` `brunch` `dessert` `dinner` `drink` `lunch` `main-course` `side-dish` `snack` * `cuisine`slug A cuisine from the closed list. 55 allowed values `african` `american` `argentinian` `asian` `australian` `austrian` `belgian` `brazilian` `british` `cajun` `caribbean` `chinese` `cuban` `danish` `dutch` `eastern-european` `egyptian` `ethiopian` `filipino` `finnish` `french` `german` `greek` `hungarian` `indian` `indonesian` `iranian` `irish` `israeli` `italian` `jamaican` `japanese` `korean` `latin-american` `lebanese` `malaysian` `mediterranean` `mexican` `middle-eastern` `moroccan` `norwegian` `pakistani` `peruvian` `polish` `portuguese` `russian` `scandinavian` `southern-us` `spanish` `swedish` `swiss` `tex-mex` `thai` `turkish` `vietnamese` * `diet`slug Only return recipes known to suit this diet, declared by the site or inferred from the required ingredients. A recipe with an unknown flag is excluded rather than guessed at. 5 allowed values `dairy-free` `gluten-free` `pescatarian` `vegan` `vegetarian` * `ingredient`slug A canonical ingredient id, such as "chicken-thigh". GET /ingredients lists them. * `maxCookMinutes`integer1–10080 Maximum cooking time in minutes, inclusive (1–10080). Uses cook time only; unknown cook time is excluded. Combine with maxTotalMinutes or time to bound the full process as well. * `maxCalories`integer1–10000 Maximum kilocalories per serving, inclusive (1–10000). Reads the nutrition the recipe was published with; a recipe without per-serving calories is excluded rather than guessed at. * `minProtein`integer1–1000 Minimum grams of protein per serving, inclusive (1–1000). Reads the nutrition the recipe was published with; a recipe without per-serving protein is excluded rather than guessed at. * `maxSodium`integer1–100000 Maximum milligrams of sodium per serving, inclusive (1–100000). Sodium published in grams is converted; a recipe without per-serving sodium is excluded. * `minFiber`integer1–200 Minimum grams of fiber per serving, inclusive (1–200). A recipe without per-serving fiber is excluded. * `nutrition`string Nutrition presets, comma-separated: high-fiber is at least 5 g of fiber, high-protein at least 20 g of protein, low-calorie at most 400 kcal, and low-sodium at most 140 mg of sodium — all per serving. A preset and an explicit amount for the same nutrient both apply, and the tighter of the two wins. Unknown presets return 400 with the accepted values. * `time`string Total-time preset: under-15 is strictly below 15 minutes, under-30 is strictly below 30 minutes, and weekend is at least 60 minutes. Unknown total time is excluded. Combines with maxTotalMinutes; weekend plus a maximum below 60 returns 400\. Unknown presets return 400 with accepted values. * `equipment`string Require every listed equipment name (1–20 comma-separated names, each at most 80 characters). Case and spaces normalize to slugs; duplicates are ignored. Examples: air fryer, slow cooker, Dutch oven, grill. Additional equipment is allowed. Unknown slugs return no matches; malformed or empty lists return 400\. Filtering happens before pagination. * `ingredients`string Require every ingredient in a comma-separated list (1–20 names or IDs, at most 80 characters each). Case and spaces normalize to slugs. Matches exact canonical IDs or whole canonical names; no substring, plural, or parent-ingredient inference. GET /ingredients provides IDs. Names without IDs can still match. Duplicates are ignored, unknown names yield no matches, and malformed lists return 400\. Combines with ingredient and all other filters before pagination. * `language`string Only return recipes written in this language, as a two-letter ISO 639-1 code. * `excludeIngredients`string Exclude any listed ingredient (1–20 comma-separated names or IDs, at most 80 characters each). Case and spaces normalize; matching uses whole canonical names or IDs, including optional ingredients. No substring, synonym, plural or parent-ingredient inference. Unknown names exclude nothing. Use ingredient=chicken-thigh&excludeIngredients=mushroom to combine inclusion and exclusion. Results reflect recorded ingredients, not an allergen guarantee. Empty or malformed lists return 400. * `limit`integerdefaults to `20`1–100 How many recipes to return. * `maxTotalMinutes`integerat least 1 Only return recipes whose total time is at most this many minutes. Recipes with no total time are excluded. * `offset`integerdefaults to `0`at least 0 How many recipes to skip. Use it with \`limit\` to page. * `without`string Leave out recipes that contain any listed allergen feature (comma-separated ids from /vocabularies). Only recipes whose \`allergens\` value is \`false\` for every listed feature are returned, and \`pagination.total\` counts only those. Informational, not medical advice. An unknown feature returns 400. ## Response `pagination`object `limit`integer How many recipes this response holds. Capped at 100. `offset`integer How many were skipped. `total`integer How many match the filter in total. Offset pagination. `recipes[]`object\[\] `allergens`objectoptional ``boolean One key per allergen identifier from GET /vocabularies, such as "milk" or "gluten-cereals": true when the recipe contains it. `disclaimer`string The required informational-use warning. Whether the recipe contains each EU and US regulated allergen: one true or false for each of the 16 allergen identifiers, keyed by identifier, beside the disclaimer. Informational only; verify product labels before serving someone with an allergy. `author`objectoptional Who wrote the recipe, and a link to them when the site published one. `categories`string\[\] Normalized category slugs from an open set, such as "pasta" or "soup". The value the \`category\` filter takes. `courses`string\[\] Course slugs from the closed list. The value the \`course\` filter takes. `createdAt`string When the recipe first entered the database. ISO 8601. `cuisines`string\[\] Cuisine slugs from the closed list. The value the \`cuisine\` filter takes. `description`stringoptional The recipe’s own summary. `dietary`objectoptional Dietary flags, declared by the site or inferred from the required ingredients. A declared flag wins; a missing flag is unknown, and false is a known no. An inferred \`glutenFree\` or \`dairyFree\` can disagree with \`allergens\` by design: the diet reads the required ingredients, so a dish is gluten-free once the optional pita is left out, while the allergen block counts every line and stays cautious. `equipment`string\[\]optional Equipment the recipe calls for, as words rather than slugs. `groups`string\[\] The section headers of the recipe: the distinct \`group\` values of the ingredients and then the steps, in the order they first appear. Empty when the recipe has no sections. `id`string The recipe id. `ingredients[]`object\[\] `display`string The line to render. Equal to the source line until the structure and the source part company — a converted unit, an amount enrichment filled in. `group`stringoptional The section header the line sat under, such as "For the sauce". `ingredientId`stringoptional The canonical ingredient id, such as "chicken-thigh". Absent until the recipe has been enriched, or when the name could not be resolved. This is the value the \`ingredient\` filter of GET /recipes takes. `localName`stringoptional The ingredient as this recipe’s own language names it, when that differs from \`name\`. `localPreparation`stringoptional How the ingredient is prepared, in the recipe’s own words, such as "finhackade" where \`preparation\` says "finely chopped". Absent on an English recipe, where \`preparation\` already is the reader’s, and on a line that says nothing of the kind. \`display\` is written with this one. `name`string The canonical English name. `note`stringoptional Anything the parser understood but could not place, such as "(400 g)". Kept as the source wrote it, in the recipe’s language, and never translated. `optional`boolean Whether the recipe marks this ingredient as optional. `original`string The source line, verbatim. Rewriting a recipe — scaling it, converting its units — leaves this alone. `preparation`stringoptional How the ingredient is prepared, in English, such as "finely chopped". Read \`localPreparation\` for the words the recipe itself uses. `quantity`objectoptional `max`numberoptional The top of a range. `unit`stringoptional One of the units listed by GET /vocabularies. `value`number The amount itself. The amount. A range such as "2-3 tomatoes" is a value of 2 with a max of 3\. A value with no unit is a count of pieces. `size`stringoptional A size qualifier, such as "large". One ingredient line, parsed. \`original\` is the line the site published; \`display\` is the same line written back from these fields, in the recipe’s own language. `instructions[]`object\[\] `duration`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `equipment`string\[\]optional Equipment slugs the step calls for. `group`stringoptional The section the step sat under or, where the page named no section, the heading the step carried of its own. `ingredients`string\[\]optional Canonical ingredient ids the step uses. `step`integer The step number. Steps always run 1, 2, 3… in order. `techniques`string\[\]optional Technique slugs the step uses, such as "saute". `temperature`objectoptional An oven or pan temperature, with its unit as "C" or "F". `text`string The step text. One step. The text is authoritative; everything else on a step comes from enrichment and may be absent. `language`string The language the recipe is written in, as a two-letter ISO 639-1 code. `media[]`object\[\] `alt`stringoptional Alternative text. `caption`stringoptional A caption published with the item. `id`string Unique within the recipe. `role`string Where the item sits in the recipe. `step`integeroptional For role "step", the step number the item illustrates. `type`string "image" or "video". `url`string The file itself. `variants`object\[\]optional The same photo in other sizes or crops. Images only. Images and videos. An image carries a \`role\` of hero, gallery, step or thumbnail; a video carries gallery or step. A recipe has at most one hero image. `notes`string\[\]optional What the writer added beside the method: storage, make-ahead, substitutions. One entry per note, in the order the page wrote them. `nutrition`objectoptional `basis`object What the numbers are per. \`type\` is "serving", "recipe" or "100g"; \`servings\` is the serving count the site worked the numbers out on, which is not always the serving count the recipe is written for; \`description\` is the serving size the site named, such as "1 cup". `calories`objectoptional Energy, with its unit. `carbohydrates`objectoptional Carbohydrates. `fat`objectoptional Fat. `fiber`objectoptional Fibre. `micronutrients`objectoptional Anything else the source declared, keyed by nutrient slug. `protein`objectoptional Protein. `saturatedFat`objectoptional Saturated fat. `sodium`objectoptional Sodium. `source`string "provided": the site published these numbers itself, in the structured data the recipe was read from, so they are as current as the last read of that page. `sugar`objectoptional Sugar. Nutrition as the site published it. \`basis\` says whether the numbers are per serving, per recipe or per 100 g. The API does not compute nutrition from the ingredients, so a recipe whose site publishes none has no nutrition object at all. `rating`objectoptional The rating the source published, with how many people rated it. `servings`objectoptional How much the recipe makes. "Serves 4-6" is a quantity of 4 with a max of 6; "Makes 24 cookies" is a quantity of 24 with a unit of "cookie". `tags`string\[\] The source site’s own keywords, cleaned but not mapped to any vocabulary. `techniques`string\[\]optional Techniques the recipe uses, as words rather than slugs. `text`object `ingredients`string\[\] One line per ingredient. `instructions`string\[\] One line per step. The recipe as plain lines: every ingredient’s \`display\` and every step’s \`text\`, in order. A convenience for rendering; nothing here is missing from the structured fields. `times`object `cook`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `inactive`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `prep`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. `total`objectoptional `seconds`integer Seconds. A length of time. Always seconds, never a formatted string. Preparation, cooking, inactive and total time, each in seconds. `title`string The recipe title. `updatedAt`string When the recipe was last written. ISO 8601. `url`string The page the recipe was read from. One source URL is one recipe. The matching recipes. Example ``` { "pagination": { "limit": 2, "offset": 0, "total": 1930 }, "recipes": [ { "allergens": { "celery": false, "crustaceans": false, "eggs": false, "fish": false, "gluten-cereals": false, "lupin": false, "milk": true, "molluscs": false, "mustard": false, "nuts-eu": false, "peanuts": true, "sesame": false, "soy": false, "sulphites": false, "tree-nuts-us": false, "wheat": false, "disclaimer": "Informational only; not medical advice. Verify ingredients and product labels before serving someone with an allergy." }, "id": "6a9820e58f8122ec891b68a3", "author": { "name": "Lindsay Ostrom", "url": "https://pinchofyum.com/about" }, "description": "This peanut butter dark chocolate hummus is a sweet alternative to traditional hummus. Perfect served on graham crackers as an afternoon snack!", "instructions": [ { "group": "Hummus", "step": 1, "text": "Blend everything through milk in a food processor." }, { "group": "Hummus", "step": 2, "text": "Add flour by the spoonful and blend until desired consistency is reached." }, { "step": 3, "text": "Stir in dark chocolate." }, { "step": 4, "text": "Chill before serving." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=225%2C225", "variants": [ { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=195%2C195" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg?fit=180%2C180" }, { "url": "https://pinchofyum.com/tachyon/2011/05/Peanut-Butter-Dark-Chocolate-Hummus.jpeg" } ] } ], "notes": [ "Keeps in an airtight container in the fridge for up to five days.", "Swap the peanut butter for almond butter to make it peanut free." ], "nutrition": { "basis": { "description": "¼ cup", "servings": 8, "type": "serving" }, "calories": { "unit": "kcal", "value": 201 }, "carbohydrates": { "unit": "g", "value": 29.4 }, "cholesterol": { "unit": "mg", "value": 0.8 }, "fat": { "unit": "g", "value": 7.4 }, "fiber": { "unit": "g", "value": 3.3 }, "micronutrients": { "trans-fat": { "unit": "g", "value": 0 } }, "protein": { "unit": "g", "value": 5.6 }, "saturatedFat": { "unit": "g", "value": 2.5 }, "sodium": { "unit": "mg", "value": 76 }, "source": "provided", "sugar": { "unit": "g", "value": 16.9 } }, "rating": { "count": 1, "reviewCount": 1, "value": 5 }, "servings": { "max": 8, "original": "6-8", "quantity": 6 }, "times": { "cook": { "seconds": 600 }, "prep": { "seconds": 300 }, "total": { "seconds": 900 } }, "title": "Peanut Butter Dark Chocolate Hummus", "categories": [], "courses": [ "dessert" ], "createdAt": "2026-09-02T13:13:09.089Z", "cuisines": [ "american" ], "groups": [ "Hummus" ], "ingredients": [ { "display": "1 can white beans or chickpeas, rinsed", "name": "white beans or chickpeas", "optional": false, "original": "1 can white beans or chickpeas, rinsed", "preparation": "rinsed", "quantity": { "unit": "can", "value": 1 } }, { "display": "¼ cup peanut butter", "name": "peanut butter", "optional": false, "original": "¼ cup peanut butter", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "2 tbsp caramel sauce", "name": "caramel sauce", "optional": false, "original": "2 tbsp caramel sauce", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "2 tbsp maple syrup", "name": "maple syrup", "optional": false, "original": "2 tbsp maple syrup", "quantity": { "unit": "tbsp", "value": 2 } }, { "display": "¼ cup brown sugar", "name": "brown sugar", "optional": false, "original": "¼ cup brown sugar", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "pinch of cinnamon", "name": "pinch of cinnamon", "optional": false, "original": "pinch of cinnamon" }, { "display": "¼ cup milk", "name": "milk", "optional": false, "original": "¼ cup milk", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "¼ cup flour", "name": "flour", "optional": false, "original": "¼ cup flour", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "chopped dark chocolate", "name": "chopped dark chocolate", "optional": false, "original": "chopped dark chocolate" } ], "tags": [ "chocolate hummus", "peanut butter hummus", "peanut butter chocolate", "hummus recipe", "dessert hummus" ], "text": { "ingredients": [ "1 can white beans or chickpeas, rinsed", "¼ cup peanut butter", "2 tbsp caramel sauce", "2 tbsp maple syrup", "¼ cup brown sugar", "pinch of cinnamon", "¼ cup milk", "¼ cup flour", "chopped dark chocolate" ], "instructions": [ "Blend everything through milk in a food processor.", "Add flour by the spoonful and blend until desired consistency is reached.", "Stir in dark chocolate.", "Chill before serving." ] }, "updatedAt": "2026-09-06T01:11:59.223Z", "url": "https://pinchofyum.com/pb-dark-chocolate-hummus" }, { "id": "6a9820e58f8122ec891b68a4", "description": "Slow-roasted cherry tomatoes are intensely sweet and tangy. Add them to salads, pastas, pizza and more.", "instructions": [ { "step": 1, "text": "Preheat the oven to 275°F (135°C) and set an oven rack in the middle position. Line a baking sheet with wide heavy-duty aluminum foil." }, { "step": 2, "text": "Directly on the lined baking sheet, using a rubber spatula, toss the tomatoes with the olive oil, vinegar, sugar, salt, pepper, and garlic. Roast for 2 hours, until the tomatoes are soft and beginning to burst. Serve hot or at room temperature." } ], "language": "en", "media": [ { "id": "hero", "role": "hero", "type": "image", "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes.jpg", "variants": [ { "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes-500x500.jpg" }, { "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes-500x375.jpg" }, { "url": "https://www.onceuponachef.com/images/2022/07/slow-roasted-cherry-tomatoes-480x270.jpg" } ] } ], "nutrition": { "basis": { "type": "serving" }, "calories": { "unit": "kcal", "value": 117 }, "carbohydrates": { "unit": "g", "value": 8 }, "fat": { "unit": "g", "value": 9 }, "fiber": { "unit": "g", "value": 2 }, "protein": { "unit": "g", "value": 1 }, "saturatedFat": { "unit": "g", "value": 1 }, "sodium": { "unit": "mg", "value": 388 }, "source": "provided", "sugar": { "unit": "g", "value": 6 } }, "rating": { "count": 25, "reviewCount": 8, "value": 4.8 }, "servings": { "original": "6", "quantity": 6 }, "times": { "cook": { "seconds": 7200 }, "prep": { "seconds": 600 }, "total": { "seconds": 7800 } }, "title": "Roasted Cherry Tomatoes", "categories": [ "vegetables-and-sides" ], "courses": [ "appetizer", "side-dish" ], "createdAt": "2026-09-02T13:13:09.118Z", "cuisines": [ "italian" ], "groups": [], "ingredients": [ { "display": "2 lb cherry tomatoes (3 pints)", "name": "cherry tomatoes", "note": "3 pints", "optional": false, "original": "2 lb cherry tomatoes (3 pints)", "quantity": { "unit": "lb", "value": 2 } }, { "display": "¼ cup extra-virgin olive oil", "name": "extra-virgin olive oil", "optional": false, "original": "¼ cup extra-virgin olive oil", "quantity": { "unit": "cup", "value": 0.25 } }, { "display": "1½ tbsp balsamic vinegar", "name": "balsamic vinegar", "optional": false, "original": "1½ tbsp balsamic vinegar", "quantity": { "unit": "tbsp", "value": 1.5 } }, { "display": "2 tsp sugar", "name": "sugar", "optional": false, "original": "2 tsp sugar", "quantity": { "unit": "tsp", "value": 2 } }, { "display": "1 tsp salt", "name": "salt", "optional": false, "original": "1 tsp salt", "quantity": { "unit": "tsp", "value": 1 } }, { "display": "½ tsp freshly ground black pepper", "name": "freshly ground black pepper", "optional": false, "original": "½ tsp freshly ground black pepper", "quantity": { "unit": "tsp", "value": 0.5 } }, { "display": "2 clove garlic (minced)", "name": "garlic", "note": "minced", "optional": false, "original": "2 clove garlic (minced)", "quantity": { "unit": "clove", "value": 2 } } ], "tags": [ "roasted cherry tomatoes" ], "text": { "ingredients": [ "2 lb cherry tomatoes (3 pints)", "¼ cup extra-virgin olive oil", "1½ tbsp balsamic vinegar", "2 tsp sugar", "1 tsp salt", "½ tsp freshly ground black pepper", "2 clove garlic (minced)" ], "instructions": [ "Preheat the oven to 275°F (135°C) and set an oven rack in the middle position. Line a baking sheet with wide heavy-duty aluminum foil.", "Directly on the lined baking sheet, using a rubber spatula, toss the tomatoes with the olive oil, vinegar, sugar, salt, pepper, and garlic. Roast for 2 hours, until the tomatoes are soft and beginning to burst. Serve hot or at room temperature." ] }, "updatedAt": "2026-09-06T01:11:59.224Z", "url": "https://www.onceuponachef.com/recipes/slow-roasted-cherry-tomatoes.html" } ] } ``` ## Errors * 400 Unknown cuisine "italien". The allowed values are listed by GET /vocabularies. A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 400 The "without" parameter must be a comma-separated list of allergen features from GET /vocabularies, such as "milk,peanuts"; got "dairy". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 403 Listing recipes requires a business plan. Use /search, /popular or /recipes/:id instead. The key is valid, but listing recipes is only available on a business plan, which this account does not have. Look recipes up with /search, /popular or /recipes/:id. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [The recipe object](https://www.tinyplates.dev/docs/recipe-object) * [Filtering and vocabularies](https://www.tinyplates.dev/docs/filtering) * [Pagination](https://www.tinyplates.dev/docs/pagination) * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Recipes * [Popular recipes](https://www.tinyplates.dev/docs/api/popular-recipes) * [Get a recipe](https://www.tinyplates.dev/docs/api/get-recipe) * [Cook from your pantry](https://www.tinyplates.dev/docs/api/pantry-recipes) * [Build a shopping list](https://www.tinyplates.dev/docs/api/shopping-list) --- title: "Ingredient substitutions — Tiny Plates recipe API" description: "What to use instead of an ingredient, in what amount and how to handle it, and when the swap does not work. An ingredient with no known swap gets no guess." url: "https://www.tinyplates.dev/docs/api/substitutions" --- # Ingredient substitutions What to use instead of an ingredient, in what amount and how to handle it, and when the swap does not work. An ingredient with no known swap gets no guess. GET`/substitutions`API key What to use instead of an ingredient. \`ingredients\` is a comma-separated list of names or canonical ids. Each option says how much of the substitute to use for one unit of the original, how to handle it, and — where it matters — what the swap cannot be used for. An ingredient nothing is known to substitute for comes back in \`unknown\`: a plausible-looking wrong ratio is worse than no answer. ## Request ``` curl 'https://api.tinyplates.dev/substitutions?ingredients=butter%2Ccream' \ -H 'Authorization: Bearer rd_your_api_key' ``` ingredients\* Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `ingredients`stringrequired The ingredients to replace: 1 to 20 comma-separated names or canonical ids, each at most 80 characters. Required. ## Response `substitutions[]`object\[\] `ingredient`string The ingredient asked about, normalized. `options`object\[\] The substitutes, each with \`ingredient\`, \`ratio\` (how much to use for one unit of the original), an optional \`note\` on handling it, and an optional \`caution\` saying what it cannot be used for. One entry per ingredient that has substitutions. `unknown`string\[\] The ingredients nothing is known to substitute for. Nothing is suggested for them. Example ``` { "substitutions": [ { "ingredient": "butter", "options": [ { "caution": "Not for creaming into a batter or for pastry, where solid fat is what makes the texture.", "ingredient": "olive oil", "note": "Use three quarters as much. The result is softer and does not brown the same way.", "ratio": 0.75 }, { "ingredient": "margarine", "note": "Use a block, not a spread: spreads carry more water.", "ratio": 1 } ] } ], "unknown": [ "saffron" ] } ``` ## Errors * 400 The "ingredients" parameter is required. Send the ingredients you want to replace, such as "butter,cream". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Reference * [List ingredients](https://www.tinyplates.dev/docs/api/list-ingredients) * [Vocabularies](https://www.tinyplates.dev/docs/api/vocabularies) --- title: "List ingredients — Tiny Plates recipe API" description: "The canonical ingredient vocabulary, most used first, with every spelling seen per language, so \"tomat\", \"Tomate\" and \"tomato\" resolve to one id." url: "https://www.tinyplates.dev/docs/api/list-ingredients" --- # List ingredients The canonical ingredient vocabulary, most used first, with every spelling seen per language, so "tomat", "Tomate" and "tomato" resolve to one id. GET`/ingredients`API key Returns the canonical ingredient vocabulary, most used first. An id from here is what the \`ingredient\` filter of GET /recipes takes. \`names\` holds the canonical English name and \`aliases\` every spelling seen, keyed by language, so "tomat", "Tomate" and "tomato" all resolve to one id. ## Request ``` curl 'https://api.tinyplates.dev/ingredients?limit=3' \ -H 'Authorization: Bearer rd_your_api_key' ``` limit Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters * `limit`integerdefaults to `100`1–500 How many ingredients to return. ## Response `ingredients[]`object\[\] `aliases`object Every spelling seen, keyed by two-letter language code. `id`string The canonical id, such as "chicken-thigh". `names`object The canonical name, keyed by two-letter language code. `recipeCount`integer How many recipes use this ingredient. The ingredients, most used first. Example ``` { "ingredients": [ { "aliases": { "en": [ "salt", "sea salt", "kosher salt", "salt and black pepper", "salt and pepper" ], "de": [ "Salz", "Jodsalz", "Bad Reichenhaller MarkenJodSalz mit Fluorid und Folsäure" ], "sv": [ "salt", "salt och svartpeppar", "salt och peppar", "flingsalt" ], "es": [ "sal", "Sal" ] }, "id": "salt", "names": { "en": "salt" }, "recipeCount": 783 }, { "aliases": { "en": [ "black pepper", "freshly ground black pepper" ], "de": [ "Pfeffer", "schwarzer Pfeffer", "frisch gemahlener Pfeffer", "gemahlener Pfeffer", "grober schwarzer Pfeffer" ], "sv": [ "peppar", "svartpeppar", "nymalen svartpeppar", "malen vitpeppar", "svartpepparkorn" ], "es": [ "pimienta", "pimienta negra molida", "Pimienta negra molida" ] }, "id": "black-pepper", "names": { "en": "black pepper" }, "recipeCount": 451 }, { "aliases": { "en": [ "garlic", "garlic clove", "garlic cloves" ], "de": [ "Knoblauchzehe", "Knoblauchzehen" ], "sv": [ "vitlöksklyfta", "vitlöksklyftor", "vitlök" ], "es": [ "Dientes de ajo", "ajo" ] }, "id": "garlic", "names": { "en": "garlic" }, "recipeCount": 411 } ] } ``` ## Errors * 400 The "limit" parameter must be a whole number between 1 and 500; got "9000". A parameter was not a value the API accepts. The message names the parameter, the value it was given and where the allowed values are listed. * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. * 500 Something went wrong. Please try again. The API could not answer. The request was not your fault; retry it, and report it if it keeps happening. See also Concepts * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Reference * [Ingredient substitutions](https://www.tinyplates.dev/docs/api/substitutions) * [Vocabularies](https://www.tinyplates.dev/docs/api/vocabularies) --- title: "Vocabularies — Tiny Plates recipe API" description: "The closed lists recipes are classified with: cuisines, courses, diets, EU and US regulated allergen features, and units. Fetch them once and cache them." url: "https://www.tinyplates.dev/docs/api/vocabularies" --- # Vocabularies The closed lists recipes are classified with: cuisines, courses, diets, EU and US regulated allergen features, and units. Fetch them once and cache them. GET`/vocabularies`API key Returns the closed lists recipes are classified with. These are the values the \`course\`, \`cuisine\` and \`diet\` filters accept, the EU and US regulated allergen features with their jurisdictions, and the units a quantity can carry. They change rarely; fetch them once and cache them. ## Request ``` curl 'https://api.tinyplates.dev/vocabularies' \ -H 'Authorization: Bearer rd_your_api_key' ``` Sign in to run this request with your own key. Free, 50 requests a day and 300 a week. [Create an account](https://www.tinyplates.dev/sign-up)[Sign in](https://www.tinyplates.dev/sign-in) ## Parameters This endpoint takes no parameters. ## Response `allergens`object\[\] The 16 EU and US regulated allergen features and their applicable jurisdictions. `courses`string\[\] The values the \`course\` filter accepts. `cuisines`string\[\] The values the \`cuisine\` filter accepts. `diets`string\[\] The values the \`diet\` filter accepts. `units`string\[\] The units a quantity can carry. Example ``` { "allergens": [ { "feature": "celery", "jurisdictions": [ "eu" ] }, { "feature": "crustaceans", "jurisdictions": [ "eu", "us" ] }, { "feature": "eggs", "jurisdictions": [ "eu", "us" ] }, { "feature": "fish", "jurisdictions": [ "eu", "us" ] }, { "feature": "gluten-cereals", "jurisdictions": [ "eu" ] }, { "feature": "lupin", "jurisdictions": [ "eu" ] }, { "feature": "milk", "jurisdictions": [ "eu", "us" ] }, { "feature": "molluscs", "jurisdictions": [ "eu" ] }, { "feature": "mustard", "jurisdictions": [ "eu" ] }, { "feature": "nuts-eu", "jurisdictions": [ "eu" ] }, { "feature": "peanuts", "jurisdictions": [ "eu", "us" ] }, { "feature": "sesame", "jurisdictions": [ "eu", "us" ] }, { "feature": "soy", "jurisdictions": [ "eu", "us" ] }, { "feature": "sulphites", "jurisdictions": [ "eu" ] }, { "feature": "tree-nuts-us", "jurisdictions": [ "us" ] }, { "feature": "wheat", "jurisdictions": [ "us" ] } ], "courses": [ "appetizer", "breakfast", "brunch", "dessert", "dinner", "drink", "lunch", "main-course", "side-dish", "snack" ], "cuisines": [ "african", "american", "argentinian", "asian", "australian", "austrian", "belgian", "brazilian", "british", "cajun", "caribbean", "chinese", "cuban", "danish", "dutch", "eastern-european", "egyptian", "ethiopian", "filipino", "finnish", "french", "german", "greek", "hungarian", "indian", "indonesian", "iranian", "irish", "israeli", "italian", "jamaican", "japanese", "korean", "latin-american", "lebanese", "malaysian", "mediterranean", "mexican", "middle-eastern", "moroccan", "norwegian", "pakistani", "peruvian", "polish", "portuguese", "russian", "scandinavian", "southern-us", "spanish", "swedish", "swiss", "tex-mex", "thai", "turkish", "vietnamese" ], "diets": [ "dairy-free", "gluten-free", "pescatarian", "vegan", "vegetarian" ], "units": [ "g", "kg", "lb", "oz", "cl", "cup", "dl", "fl-oz", "gallon", "l", "ml", "pint", "quart", "tbsp", "tsp", "bag", "bottle", "box", "bunch", "can", "clove", "cube", "dash", "drop", "ear", "handful", "head", "jar", "knob", "leaf", "package", "packet", "piece", "pinch", "portion", "pot", "scoop", "sheet", "shot", "slice", "sprig", "stalk", "stick", "tub", "cm", "inch" ] } ``` ## Errors * 401 An API key is required. Pass it as an Authorization: Bearer header. No key was sent. Every endpoint except the root, /health, /docs and /openapi.json requires one. * 401 Invalid API key. The key does not exist. Check for a truncated copy, or create a new one on your dashboard. * 401 This API key has been disabled. The key was revoked. Create a new one on your dashboard. * 401 This API key has expired. The key was created with an expiry that has passed. Create a new one. * 429 Daily allowance of 50 requests used. It resets at midnight UTC. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 50 requests for the day. The allowance is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly allowance of 300 requests used. It covers the last 7 days. Paid plans include more; see https://www.tinyplates.dev/pricing. The account has used its 300 requests over the last 7 days, today included. The allowance is per account, so another key will not help. Room comes back as older days drop out of the window. * 429 Daily limit of 5,000 requests on the Personal plan reached. It resets at midnight UTC. Contact us for a higher limit. The account has used its plan's limit for the day. The message names the number and the plan, which differ between accounts. The limit is per account, so another key will not help. It resets at midnight UTC. * 429 Weekly limit of 30,000 requests on the Business plan reached. It covers the last 7 days. Contact us for a higher limit. The account has used the weekly limit set on it over the last 7 days, today included. The message names the number and the plan. Only accounts with a weekly limit can see this. Room comes back as older days drop out of the window. See also Concepts * [Authentication](https://www.tinyplates.dev/docs/authentication) * [Errors](https://www.tinyplates.dev/docs/errors) * [Rate limits](https://www.tinyplates.dev/docs/rate-limits) Reference * [Ingredient substitutions](https://www.tinyplates.dev/docs/api/substitutions) * [List ingredients](https://www.tinyplates.dev/docs/api/list-ingredients) --- title: "Tiny Plates facts" description: "Tiny Plates in plain facts: what the recipe API serves, what it costs, its limits, how to sign in, how the recipes may be used and how to reach us." url: "https://www.tinyplates.dev/facts" --- Tiny Plates / Facts # Facts Everything worth knowing about the recipe API, one line each. ## At a glance * **What it is:** A recipe API and MCP server for apps and AI agents. * **Price:** A free plan with no credit card. Personal is $5 a month and Business $20, with extra requests at $1 per 1,000. * **Limits:** Free: 50 requests a day and 300 a week. Personal includes 5,000 requests a month and Business 20,000\. Enterprise on request. * **Recipes:** Thousands, gathered from public recipe pages. * **Languages:** Recipes in English, Spanish and Swedish. * **Ingredients:** Quantity, unit, name and preparation in separate fields, with canonical ingredient ids shared across languages. * **Steps:** Numbered steps in the response. * **Allergens:** True or false for each of the EU’s 14 regulated allergens, plus the US definitions of wheat and tree nuts. Informational only. * **Search:** By meaning as well as wording. * **Beyond recipes:** Pantry matching, shopping lists grouped by aisle, serving scaling, metric and imperial conversion, and substitutions. * **Attribution:** Credit the source and link to the recipe’s source URL. * **Caching:** Cache the recipes your users ask for. Copying the index in bulk is not allowed. * **AI use:** Agents and LLM apps may call the API at run time. Training a model on the recipes, or bulk access, needs our permission first. * **Uptime:** No uptime promise. ## Connecting * REST API: `https://api.tinyplates.dev`, with the key sent as a bearer token. * OpenAPI 3.1: [openapi.json](https://api.tinyplates.dev/openapi.json) * MCP server: `https://api.tinyplates.dev/mcp`, signed in to with your account or an API key. See [connecting an agent](https://www.tinyplates.dev/docs/mcp). * Keys: free from [sign-up](https://www.tinyplates.dev/sign-up). ## For agents [/llms.txt](https://www.tinyplates.dev/llms.txt) lists every page worth reading, and [/llms-full.txt](https://www.tinyplates.dev/llms-full.txt) has the documentation in one file. Every page also has a Markdown copy at its address plus `.md`. ## Contact Tiny Plates is a small, independent service. Write to [chris@pullpanda.io](mailto:chris@pullpanda.io) about anything: higher limits, bulk access, a takedown or a bug. The [changelog](https://www.tinyplates.dev/changelog) lists what has changed and the [status page](https://www.tinyplates.dev/status) shows whether the API is up. --- title: "Frequently asked questions — Tiny Plates" description: "Answers to the questions people ask most about Tiny Plates: price, limits, languages, allergens, AI agents and MCP, attribution and commercial use." url: "https://www.tinyplates.dev/faq" --- Tiny Plates / Questions # Questions Short answers about the recipe API, its limits and how the recipes may be used. ## The basics ### What is Tiny Plates? Tiny Plates is a recipe API and MCP server. It serves thousands of recipes from public recipe sites in one structured shape: ingredients split into quantity, unit and name, numbered steps, times, servings, nutrition, diets and allergen flags. ### Is the Tiny Plates recipe API free? There is a free plan, and it needs no credit card. For more requests, Personal is $5 a month and Business $20, with extra requests at $1 per 1,000\. Prices are before tax. See https://www.tinyplates.dev/pricing. ### How many requests can I make? On Free, 50 requests a day and 300 a week, shared by all of the account's keys. Personal includes 5,000 requests a month and Business 20,000\. If you need more than 20,000 a day, write to chris@pullpanda.io and say what you are building. ### Do I need an API key? Yes. Create a free account, make a key in the dashboard and send it as a bearer token in the Authorization header. ### What is the API base URL? https://api.tinyplates.dev. The full API is described in OpenAPI 3.1 at https://api.tinyplates.dev/openapi.json. ## The recipes ### Which languages are the recipes in? English, Spanish and Swedish. Every ingredient also gets a canonical English name, so the same ingredient matches across languages. ### Does the API flag allergens? Yes. Each recipe says true or false for the 14 allergens the EU regulates, plus the US definitions of wheat and tree nuts. The flags are worked out by software from the ingredient list, so treat them as information and check the source before relying on them for an allergy. ### How does recipe search work? By meaning as well as wording, so a search for "creamy pasta" also finds carbonara. You can filter by time, diet, allergens, nutrition, equipment and ingredients to include or leave out. ### Can it do more than return recipes? Yes. The API matches recipes to a pantry, scales servings, converts between metric and imperial, suggests substitutions and merges several recipes into one shopping list grouped by aisle. ### Where do the recipes come from? From the structured data public recipe pages already publish for search engines. Every recipe links back to its source and credits its author. ## AI agents ### Can AI agents use Tiny Plates? Yes. Tiny Plates runs an MCP server at https://api.tinyplates.dev/mcp over streamable HTTP. Agents such as Claude, ChatGPT, Cursor and VS Code can connect to it and sign in with your Tiny Plates account, or send an API key. ### Can my AI app call the API at run time? Yes. Agents and LLM apps may call the API while they answer a user, the same as any other app, as long as they credit the recipe source. ### Can I train a model on the recipes? Not without asking first. To train a model on the recipes, or for bulk access to the dataset, write to chris@pullpanda.io. There is often a way to say yes. ## Using the recipes ### Can I use Tiny Plates in a commercial app? Yes, as long as you keep to the terms: credit the recipe source, link to it, and do not copy the index in bulk. ### How do I credit a recipe? Credit the source and link to the URL in the recipe’s source field wherever you show the recipe. ### Can I cache recipes? Yes, cache the recipes your users ask for and let the cache expire. Building your own copy of the index is not allowed. ### Is there an uptime guarantee? No. No plan comes with an uptime promise yet. The status page shows whether the API is answering right now. ### I publish recipes. How do I opt out? Write to chris@pullpanda.io and your site will be removed. --- title: "About Tiny Plates and its recipe API" description: "Tiny Plates turns recipes from across the web into structured, consistent data — a free recipe API to build apps and agents on." url: "https://www.tinyplates.dev/about" --- Tiny Plates / Our purpose # About Recipes are published as prose. We turn them into data you can build on. ## What you get Thousands of recipes in one shape. Ingredients parsed into quantities, units and canonical names. Steps numbered in order. Times in seconds. Servings, nutrition, dietary flags and media in fixed fields. Cuisines and courses from closed lists, so a filter means the same thing on every recipe. It is a read API with semantic search, meant for apps, agents and anything else that needs recipes it can actually compute with. On top of single recipes it can scale servings, convert between metric and imperial, match recipes to what is in a pantry, suggest substitutions, and merge several recipes into one shopping list. ## How a recipe gets in A recipe starts as the structured data a recipe page already publishes for search engines. We read it, normalize it into one model, and then have a language model split every ingredient line into a quantity, a unit, a canonical name and a preparation, in the recipe’s own language and in English. After that, each ingredient is checked against the EU’s 14 regulated allergens and the US definitions of wheat and tree nuts, and the recipe is tagged with the diets it suits. Last, it is embedded for search, which is why a query for “creamy pasta” also finds carbonara. ## Where the recipes come from Public recipe pages. Every recipe links back to its source and credits its author. Publishers who would rather not be included can write to [chris@pullpanda.io](mailto:chris@pullpanda.io). ## Start building The free plan comes with 50 requests a day and 300 a week, and the [paid plans](https://www.tinyplates.dev/pricing) include more. The [quickstart](https://www.tinyplates.dev/docs/quickstart) gets you a response in a couple of minutes, and you can run every endpoint straight from the [documentation](https://www.tinyplates.dev/docs). --- title: "Terms of service — Tiny Plates" description: "The terms for using the Tiny Plates API: one account, keys you keep to yourself, 50 requests a day and 300 a week, and attribution for the recipes you serve on." url: "https://www.tinyplates.dev/terms" --- Tiny Plates / The details # Terms of service Plain terms for the API. Using it means agreeing to them. ## Your account You need an account to get an API key. Keep your password and your keys to yourself — anything done with your key counts as done by you. If a key leaks, revoke it from your [dashboard](https://www.tinyplates.dev/dashboard/keys); that takes effect at once. One account per person or organisation. Do not create accounts to work around the rate limit. ## Using the API On the free plan your account gets 50 requests a day and 300 a week across all of its keys. The [paid plans](https://www.tinyplates.dev/pricing) include more, as described under [rate limits](https://www.tinyplates.dev/docs/rate-limits). Stay within them, and cache what does not change rather than re-requesting it. Do not: * attempt to disrupt the service, or work around its limits or authentication; * resell the API itself, or pass it off as your own service; * systematically copy the index — paging through the endpoints to build your own database of it, walking the id space, or spreading that work across accounts, keys or addresses; * use it for anything unlawful. The last one is the line we care most about. This API is for looking up the recipes your users actually ask for. Cache those and let the cache expire — what is not allowed is accumulating the corpus until you have a copy of it. If you want the dataset in bulk, ask us at [chris@pullpanda.io](mailto:chris@pullpanda.io) rather than taking it a page at a time; there is often a way to say yes. AI agents and LLM apps are welcome to call the API while they answer a user, under the same terms as any other app. Training a model on the recipes counts as bulk use, so ask us first. ## The recipes The recipes belong to the people and sites that published them, not to us. We normalize them and link back. If you display a recipe you got from this API, credit its source and link to the `source.url` the response carries. Nothing here grants you rights in a recipe beyond what its publisher allows. Bulk-republishing whole recipes as your own is not something this API can give you permission to do. Publishers: to have your site removed, write to [chris@pullpanda.io](mailto:chris@pullpanda.io). ## No warranty The service is provided as it is. Recipes are gathered automatically and normalized by software, and both can be wrong — an ingredient misparsed, a time missing, a dietary flag inferred rather than declared. Nutrition and dietary information in particular is not reliable enough to depend on for health or allergy decisions. Check against the source before you rely on anything. We do not promise the API will be available, complete or uninterrupted, and we are not liable for losses arising from its use, so far as the law allows. ## Ending it You can stop using the API at any time and ask us to delete your account — see [privacy](https://www.tinyplates.dev/privacy). We may suspend an account that breaks these terms, and will say why where we can. ## Changes These terms may change as the service does. Material changes will be posted here before they take effect, and keys will not be made required without notice — see [authentication](https://www.tinyplates.dev/docs/authentication). --- title: "Changelog — Tiny Plates" description: "What has changed in the Tiny Plates recipe API, MCP server and documentation, newest first." url: "https://www.tinyplates.dev/changelog" --- Tiny Plates / Changelog # Changelog What has changed in the recipe API, the MCP server and the docs, newest first. ## 17 October 2026: Paid plans * Personal at $5 a month and Business at $20, each with a block of requests included and extra requests at $1 per 1,000\. The free plan stays. The pricing page has a calculator. * Upgrade, change plan or cancel from the billing page in the dashboard. * Listing the whole database comes with Business. ## 15 October 2026: Meal Planner and glossary recipes * A Meal Planner example plans a week of lunches and dinners. * Each glossary term lists recipes from the API that use it. ## 14 October 2026: Kitchen glossary and Fridge Roulette * A kitchen glossary explains cooking terms, techniques and equipment. * Fridge Roulette, an example app that finds a recipe from what is in your fridge, can be tried on its own page and inside blog posts. ## 12 October 2026: Blog * The Tiny Plates blog has guides to building with recipe data. ## 30 September 2026: Recipe API comparisons * New pages compare Tiny Plates with other recipe APIs on price, limits, data and terms. ## 28 September 2026: Recipe sections * Recipes keep their ingredient and step groups, such as "For the sauce". ## 27 September 2026: A new dashboard * The dashboard has a home page, and the key and usage tables are easier to read. ## 21 September 2026: Data quality fixes and diets * Unit conversion, rounding, nutrition totals, search and pantry matching were fixed after a data-quality audit. * Diets are worked out from the ingredients, and a garnish no longer marks a recipe as containing an allergen. ## 19 September 2026: API keys on every request * Every data endpoint needs an API key. Keys are free from the dashboard. * Each account gets 50 requests a day and 300 a week. ## 17 September 2026: Allergen flags * Every recipe says whether it contains each of the EU's 14 regulated allergens, plus the US definitions of wheat and tree nuts, with the ingredients behind each flag. * `/search` also accepts the `QUERY` method, for searches too long for a URL. * `/health` reports the running version and when it started. ## 16 September 2026: MCP guides and the shopping list example * The docs explain how to connect Claude, ChatGPT, Cursor, VS Code and other agents to the MCP server, and long tool results come in pages. * A shopping list builder example shows recipes merging into one list grouped by aisle. ## 15 September 2026: MCP server * The API is available as an MCP server, so AI agents can search and read recipes. Agents sign in with your Tiny Plates account. ## 14 September 2026: Spanish and Swedish * The site has Spanish and Swedish versions, for builders working with recipes in those languages. ## 7 September 2026: Pantry search, scaling and shopping lists * Pantry search finds recipes you can cook with what you have, and can filter by how many ingredients are missing. * Scale a recipe to a different number of servings. * Convert a recipe between metric and imperial units. * Build one shopping list from several recipes. * Nutrition per serving and for the whole recipe, with filters by calories, protein and nutrition presets. * Ingredient substitutions. * API keys are sent as bearer tokens. ## 6 September 2026: API reference and recipe search filters * The developer portal has a full API reference, and every endpoint can be tried from the docs. * Search recipes by total time, by the ingredients they use and by the ingredients they leave out. * Filter recipes by the equipment they need. --- title: "Status — Tiny Plates" description: "Whether the Tiny Plates recipe API and MCP server are answering right now, and how quickly." url: "https://www.tinyplates.dev/status" --- Tiny Plates / Status # Status Everything is answering. ## Right now * **Recipe API**: Up, 126 ms Running version 1930edf, started 2026-10-19T04:38:40.603Z. `https://api.tinyplates.dev/health` * **MCP server**: Up, 126 ms Answering requests. `https://api.tinyplates.dev/mcp` Checked from our server at 2026-10-19 05:10:25 UTC. Reload the page to check again. ## What this covers The recipe API is checked through its health endpoint and the MCP server by asking it for its sign-in. No plan comes with an uptime promise yet, but if something is down for long, write to us and we will look. --- title: "Best recipe APIs compared — Tiny Plates" description: "Recipe APIs compared: Tiny Plates, Spoonacular, Edamam, TheMealDB and the Tasty API, with prices and limits from their own pages, and the ones that have closed." url: "https://www.tinyplates.dev/compare" --- Tiny Plates / Compare # Recipe APIs compared The recipe APIs you can sign up for today, what each is good at, and the ones that have closed. We make one of them, so we say where the others are the better pick. ## Still running * **Spoonacular.** The broadest food API: recipes, grocery products, menu items and meal plans. Paid plans from $29 a month. Cached data must be deleted after an hour. [Tiny Plates vs Spoonacular](https://www.tinyplates.dev/compare/spoonacular) * **Edamam.** Over 2 million web recipes. Plans from $9 a month and no free plan. Web recipes link out for the cooking steps. [Tiny Plates vs Edamam](https://www.tinyplates.dev/compare/edamam) * **TheMealDB.** A community recipe database with 793 meals. Free to develop against, $10 once to release publicly. Ingredients and measures are plain text. [Tiny Plates vs TheMealDB](https://www.tinyplates.dev/compare/themealdb) * **Tasty.** Tasty’s recipes through a third-party listing on RapidAPI. Plans and quotas are set there. [Tiny Plates vs Tasty](https://www.tinyplates.dev/compare/tasty) ## Closed Older lists still recommend these. Do not plan a product around them. * **Yummly.** Closed. The API shut in September 2019 and the app and website went offline in December 2024\. [What replaces the Yummly API](https://www.tinyplates.dev/compare/yummly) ## Where Tiny Plates fits Tiny Plates is the smallest and newest API on this page. It is for apps and agents that need to compute with a recipe, not only show it. It is not the one to pick for grocery products or high volume. * A free plan with no credit card. Personal is $5 a month and Business $20, with extra requests at $1 per 1,000. * Free: 50 requests a day and 300 a week. Personal includes 5,000 requests a month and Business 20,000\. Enterprise on request. * Thousands, gathered from public recipe pages. * Quantity, unit, name and preparation in separate fields, with canonical ingredient ids shared across languages. * True or false for each of the EU’s 14 regulated allergens, plus the US definitions of wheat and tree nuts. Informational only. * Pantry matching, shopping lists grouped by aisle, serving scaling, metric and imperial conversion, and substitutions. * Recipes in English, Spanish and Swedish. * An MCP server for agents, signed in to with your account. * No uptime promise. [Create a free account](https://www.tinyplates.dev/sign-up) or read the [documentation](https://www.tinyplates.dev/docs). ## How we checked Prices, limits and terms were read from each API’s own pages in September 2026\. If something has changed, write to [chris@pullpanda.io](mailto:chris@pullpanda.io) and we will correct it. --- title: "Tiny Plates vs Spoonacular: a Spoonacular alternative" description: "Tiny Plates and Spoonacular compared: price, points and requests, caching rules, allergens and ingredient data, and how the requests map." url: "https://www.tinyplates.dev/compare/spoonacular" --- Tiny Plates / Compare # Tiny Plates vs Spoonacular Spoonacular covers more ground: grocery products, restaurant menus and meal plans. Tiny Plates costs less and goes deeper on the recipe itself. ## What Spoonacular is Spoonacular is the widest food API you can sign up for. One key covers recipe search, grocery products, restaurant menu items, meal plans and shopping lists. It charges in points rather than requests, and its terms limit how long you may keep what you fetch. ## At a glance | Feature | Tiny Plates | Spoonacular | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | Price | Tiny Plates: A free plan with no credit card. Personal is $5 a month and Business $20, with extra requests at $1 per 1,000. | Spoonacular: Free plan, then $29, $79 and $149 a month. Enterprise from $300. | | Free allowance | Tiny Plates: Free: 50 requests a day and 300 a week. Personal includes 5,000 requests a month and Business 20,000\. Enterprise on request. | Spoonacular: 50 points a day, with a backlink to Spoonacular required. | | Recipes | Tiny Plates: Thousands, gathered from public recipe pages. | Spoonacular: Its site lists 5,000+ recipes, 600K+ products and 115K+ menu items. | | Allergens | Tiny Plates: True or false for each of the EU’s 14 regulated allergens, plus the US definitions of wheat and tree nuts. Informational only. | Spoonacular: Detects common allergens such as wheat, dairy, eggs, soy and nuts. | | Ingredients | Tiny Plates: Quantity, unit, name and preparation in separate fields, with canonical ingredient ids shared across languages. | Spoonacular: Ingredient data, substitutions and unit conversion. | | Beyond recipes | Tiny Plates: Pantry matching, shopping lists grouped by aisle, serving scaling, metric and imperial conversion, and substitutions. | Spoonacular: Meal planning, shopping lists, products and menu items. | | Caching | Tiny Plates: Cache the recipes your users ask for. Copying the index in bulk is not allowed. | Spoonacular: One hour at most, with written permission. Only the recipe id, title and image URL may be kept longer. | | Attribution | Tiny Plates: Credit the source and link to the recipe’s source URL. | Spoonacular: Credit the original source with a link. | | Uptime promise | Tiny Plates: No uptime promise. | Spoonacular: 99% on the $29 and $79 plans, 99.9% from $149. | | MCP server | Tiny Plates: An MCP server for agents, signed in to with your account. | Spoonacular: Yes. | ## What is different ### Points or requests Spoonacular counts points. A recipe search costs 1 point plus 0.01 for each result, and some options add more. The free plan has 50 points a day. Tiny Plates counts requests: one call is one request, whatever it returns. ### How long you can keep a recipe Spoonacular’s terms let you cache data for at most an hour, with written permission, and ask you to delete everything if you stop using the API. Only the recipe id, title and image URL can stay. Tiny Plates lets you cache the recipes your users ask for. What it does not allow is copying the index in bulk. ### Allergens Spoonacular detects common allergens and has an intolerances filter. Tiny Plates answers true or false for each of the EU’s 14 regulated allergens and the US definitions of wheat and tree nuts, and the “without” parameter leaves out recipes that contain any you list. ### Products and menus Spoonacular also lists 600K+ grocery products and 115K+ menu items from US restaurant chains. Tiny Plates has neither. It does recipes only. ## Moving from Spoonacular The same tasks as requests to each API. The [documentation](https://www.tinyplates.dev/docs) has every parameter. | Task | Spoonacular | Tiny Plates | | ------------------------ | ----------------------------------------------------------------------- | ------------------------------------------------- | | Search recipes | Spoonacular: GET /recipes/complexSearch?query=pasta | Tiny Plates: GET /search?query=pasta | | Leave out an allergen | Spoonacular: GET /recipes/complexSearch?query=pasta&intolerances=dairy | Tiny Plates: GET /search?query=pasta&without=milk | | Find by cuisine and diet | Spoonacular: GET /recipes/complexSearch?cuisine=italian&diet=vegetarian | Tiny Plates: GET /search?query=vegetarian italian | | Cook from what you have | Spoonacular: GET /recipes/findByIngredients?ingredients=chicken,rice | Tiny Plates: GET /pantry?ingredients=chicken,rice | | Get one recipe | Spoonacular: GET /recipes/{id}/information | Tiny Plates: GET /recipes/{id} | ## Pick Spoonacular when * You need grocery products or restaurant menu items from the same API. * You need meal planning built in. * You need an uptime promise. ## Pick Tiny Plates when * You want ingredient ids that mean the same thing in English, Spanish and Swedish recipes. * You filter on the EU’s 14 allergens, not only the common ones. * You want to cache the recipes your users open without a one-hour limit. * You want a free account without a backlink requirement for the API itself. * You want paid plans from $5 a month, not $29. ## Questions ### Is there a free alternative to Spoonacular? Tiny Plates has a free plan, with 50 requests a day and 300 a week, and paid plans from $5 a month. Spoonacular has a free plan too, with 50 points a day and a required backlink. ### Can I cache Spoonacular data? For at most one hour, and with written permission. The recipe id, title and image URL may be kept longer. ### Can I use both? Yes. They cover different ground: Tiny Plates for the recipe itself, Spoonacular for grocery products and restaurant menus. ### Do I need an API key for Tiny Plates? Yes. Create a free account, make a key in the dashboard and send it as a bearer token. ## Try it [Create a free account](https://www.tinyplates.dev/sign-up) and follow the [quickstart](https://www.tinyplates.dev/docs/quickstart) to get a response in a couple of minutes. The [terms](https://www.tinyplates.dev/terms) say what you may cache and how to credit a recipe, and [the overview](https://www.tinyplates.dev/compare) lists the other recipe APIs. --- title: "Tiny Plates vs Edamam: an Edamam recipe API alternative" description: "Tiny Plates and the Edamam Recipe Search API compared: price, cooking instructions, caching rules and ingredient data, and how the requests map." url: "https://www.tinyplates.dev/compare/edamam" --- Tiny Plates / Compare # Tiny Plates vs Edamam Edamam has far more recipes. Tiny Plates starts free and returns the full recipe, steps included. ## What Edamam is Edamam sells several food APIs separately. This page is about its Recipe Search API, which indexes over 2 million recipes from around the web. Edamam does not hold a licence to most of them, so the API links out to the source for the cooking steps. ## At a glance | Feature | Tiny Plates | Edamam | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | | Price | Tiny Plates: A free plan with no credit card. Personal is $5 a month and Business $20, with extra requests at $1 per 1,000. | Edamam: $9 a month for 10,000 calls, $99 for 500,000, $399 for 1 million, then custom. No free plan; some plans have a 10-day trial. | | Allowance | Tiny Plates: Free: 50 requests a day and 300 a week. Personal includes 5,000 requests a month and Business 20,000\. Enterprise on request. | Edamam: 10,000 calls a month on the smallest plan. | | Recipes | Tiny Plates: Thousands, gathered from public recipe pages. | Edamam: Over 2 million web recipes. The $399 plan serves 20,000 Edamam-owned recipes instead. | | Cooking instructions | Tiny Plates: Numbered steps in the response. | Edamam: Web recipes link out to the source. Instructions come only with the Edamam-owned recipes on the $399 plan. | | Caching | Tiny Plates: Cache the recipes your users ask for. Copying the index in bulk is not allowed. | Edamam: Recipe id and name only. From $99 a month, also calories, protein, fat and net carbs. | | Attribution | Tiny Plates: Credit the source and link to the recipe’s source URL. | Edamam: Required on every plan. | ## What is different ### Where the cooking steps are On the $9 and $99 plans, Edamam returns web recipes without cooking instructions and links to the source. Instructions come with the 20,000 Edamam-owned recipes on the $399 plan. Tiny Plates returns numbered steps with every recipe. ### What you may store Edamam lets you cache the recipe id and name, and from the $99 plan four figures: calories, protein, fat and net carbs. Tiny Plates lets you cache the recipes your users ask for, ingredients and steps included. What it does not allow is copying the index in bulk. ### Free plan or trial The Recipe Search API has no free plan. Some plans have a 10-day trial. Tiny Plates has a free plan with no trial period, and paid plans from $5 a month. ### Size Edamam’s index is far larger: over 2 million recipes against our thousands. If finding every dish matters most, that decides it. ## Moving from Edamam The same tasks as requests to each API. The [documentation](https://www.tinyplates.dev/docs) has every parameter. | Task | Edamam | Tiny Plates | | ------------------------ | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | Search recipes | Edamam: GET /api/recipes/v2?type=public&q=pasta | Tiny Plates: GET /search?query=pasta | | Find by cuisine and diet | Edamam: GET /api/recipes/v2?type=public&q=pasta&cuisineType=Italian&health=vegetarian | Tiny Plates: GET /search?query=vegetarian italian pasta | | Limit the cooking time | Edamam: GET /api/recipes/v2?type=public&q=pasta&time=30 | Tiny Plates: GET /search?query=quick pasta, then check times.total | | Authenticate | Edamam: app\_id and app\_key query parameters | Tiny Plates: Authorization: Bearer header | ## Pick Edamam when * You need a corpus of millions of recipes. * You need hundreds of thousands of calls a month at a flat price. ## Pick Tiny Plates when * You want the cooking steps in the response without a $399 plan. * You want parsed ingredients with canonical ids, scaling and unit conversion. * You want to start free, without a trial that runs out. ## Questions ### Does the Edamam Recipe Search API return cooking instructions? Only for the 20,000 Edamam-owned recipes on the $399 plan. For web recipes it links to the source. ### Does Edamam have a free plan? Not for Recipe Search. Plans start at $9 a month, and some have a 10-day trial. ### Can I cache Edamam recipes? Only the recipe id and name, plus calories, protein, fat and net carbs from the $99 plan. ### Do I need an API key for Tiny Plates? Yes. Create a free account, make a key in the dashboard and send it as a bearer token. ## Try it [Create a free account](https://www.tinyplates.dev/sign-up) and follow the [quickstart](https://www.tinyplates.dev/docs/quickstart) to get a response in a couple of minutes. The [terms](https://www.tinyplates.dev/terms) say what you may cache and how to credit a recipe, and [the overview](https://www.tinyplates.dev/compare) lists the other recipe APIs. --- title: "Tiny Plates vs TheMealDB: a TheMealDB alternative" description: "Tiny Plates and TheMealDB compared: catalogue size, ingredient structure, search, allergens and price, and how the requests map." url: "https://www.tinyplates.dev/compare/themealdb" --- Tiny Plates / Compare # Tiny Plates vs TheMealDB TheMealDB is the simplest way to get a recipe on screen. Tiny Plates is for when the app needs to compute with the recipe. ## What TheMealDB is TheMealDB is a community-built recipe database with a free JSON API. It is a common first recipe API: there is a test key, no sign-up, and a handful of simple endpoints. ## At a glance | Feature | Tiny Plates | TheMealDB | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | Price | Tiny Plates: A free plan with no credit card. Personal is $5 a month and Business $20, with extra requests at $1 per 1,000. | TheMealDB: Free test key for development and teaching. A $10 one-off supporter payment to release an app publicly. | | Allowance | Tiny Plates: Free: 50 requests a day and 300 a week. Personal includes 5,000 requests a month and Business 20,000\. Enterprise on request. | TheMealDB: No stated quota. | | Recipes | Tiny Plates: Thousands, gathered from public recipe pages. | TheMealDB: 793 meals when we checked. | | Ingredients | Tiny Plates: Quantity, unit, name and preparation in separate fields, with canonical ingredient ids shared across languages. | TheMealDB: Up to 20 ingredient names per meal, each with a free-text measure. | | Cooking instructions | Tiny Plates: Numbered steps in the response. | TheMealDB: One block of text. | | Search | Tiny Plates: By meaning as well as wording. | TheMealDB: By name, first letter, main ingredient, category or area. Filtering on several ingredients is for supporters. | | Allergens | Tiny Plates: True or false for each of the EU’s 14 regulated allergens, plus the US definitions of wheat and tree nuts. Informational only. | TheMealDB: None. | ## What is different ### Ingredients as text or as data TheMealDB lists up to 20 ingredient names per meal, each with a measure written as text. To scale a recipe or add up a shopping list you parse those yourself. Tiny Plates returns quantity, unit, name and preparation as separate fields, and scales the recipe or builds the shopping list for you. ### Finding a recipe TheMealDB searches by meal name or first letter, and filters by one ingredient, category or area. Tiny Plates searches by meaning, so “quick vegetarian dinner” works. It also finds recipes from the ingredients you have, and leaves out any allergen you list. ### Size and going public TheMealDB had 793 meals when we checked. Its test key is for development and education, and releasing an app publicly needs the $10 supporter upgrade. Tiny Plates has thousands of recipes, and a free account covers a public app within the daily allowance. ## Moving from TheMealDB The same tasks as requests to each API. The [documentation](https://www.tinyplates.dev/docs) has every parameter. | Task | TheMealDB | Tiny Plates | | -------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------- | | Search by name | TheMealDB: GET …/search.php?s=Arrabiata | Tiny Plates: GET /search?query=arrabiata | | Get one recipe | TheMealDB: GET …/lookup.php?i=52772 | Tiny Plates: GET /recipes/{id} | | Filter by ingredient | TheMealDB: GET …/filter.php?i=chicken\_breast | Tiny Plates: GET /pantry?ingredients=chicken | | Find by cuisine | TheMealDB: GET …/filter.php?a=Italian | Tiny Plates: GET /search?query=italian | | Match several ingredients (supporters only on TheMealDB) | TheMealDB: GET …/filter.php?i=chicken,rice | Tiny Plates: GET /pantry?ingredients=chicken,rice | ## Pick TheMealDB when * You are learning, teaching or building a demo. * You want no sign-up and no daily allowance. * A few hundred recipes are enough. ## Pick Tiny Plates when * You need quantities and units as data, to scale a recipe or build a shopping list. * You need to leave out allergens, or know which recipes are vegetarian or vegan. * You need search that understands “quick vegetarian dinner”, not only a dish name. * You need recipes in Spanish or Swedish. ## Questions ### Is TheMealDB free for commercial use? The test key is for development and education. Releasing an app publicly needs the supporter upgrade, a one-off $10. ### How many recipes does TheMealDB have? 793 meals when we checked in September 2026. ### Do I need an API key for Tiny Plates? Yes. Create a free account, make a key in the dashboard and send it as a bearer token. ## Try it [Create a free account](https://www.tinyplates.dev/sign-up) and follow the [quickstart](https://www.tinyplates.dev/docs/quickstart) to get a response in a couple of minutes. The [terms](https://www.tinyplates.dev/terms) say what you may cache and how to credit a recipe, and [the overview](https://www.tinyplates.dev/compare) lists the other recipe APIs. --- title: "Tiny Plates vs the Tasty API: a Tasty API alternative" description: "Tiny Plates and the Tasty API on RapidAPI compared: who runs it, how you sign up, where its plans are set, and what the recipe data looks like." url: "https://www.tinyplates.dev/compare/tasty" --- Tiny Plates / Compare # Tiny Plates vs Tasty The Tasty API on RapidAPI is a third-party listing of Tasty’s recipes. Tiny Plates is an API we run ourselves, built for structured recipe data. ## What Tasty is Tasty is BuzzFeed’s food brand, known for its recipe videos. The Tasty API on RapidAPI is a listing published by Api Dojo that returns Tasty’s recipe data. You subscribe to it through RapidAPI. ## At a glance | Feature | Tiny Plates | Tasty | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- | | Who runs it | Tiny Plates: We run the API and the pipeline behind it. | Tasty: Api Dojo, a publisher on RapidAPI. The listing is not BuzzFeed’s own. | | Sign-up | Tiny Plates: A Tiny Plates account. | Tasty: A RapidAPI account and a subscription to the listing. | | Price | Tiny Plates: A free plan with no credit card. Personal is $5 a month and Business $20, with extra requests at $1 per 1,000. | Tasty: Plans and quotas are set on the RapidAPI listing. | | Allowance | Tiny Plates: Free: 50 requests a day and 300 a week. Personal includes 5,000 requests a month and Business 20,000\. Enterprise on request. | Tasty: Depends on the plan. | | Recipes | Tiny Plates: Thousands, gathered from public recipe pages. | Tasty: Recipes from Tasty. | ## What is different ### Who you depend on The listing is published by Api Dojo on RapidAPI. If you build on it, you depend on that publisher and on the marketplace. Tiny Plates runs its own API and the pipeline behind it, and you sign up with us directly. ### One brand’s recipes or a normalized index The Tasty API returns Tasty’s own recipes. Tiny Plates has none of Tasty’s content. It gathers recipes from public recipe pages and normalizes them into one model, with parsed ingredients, allergens and numbered steps. ## Pick Tasty when * You want Tasty’s own recipes. Tasty is known for its recipe videos, and we have none of its content. * You already buy your APIs through RapidAPI. ## Pick Tiny Plates when * You want to deal with the people who run the API. * You need parsed ingredients, allergens, scaling or shopping lists. * You want a free account without a marketplace subscription. ## Questions ### Who publishes the Tasty API? The listing on RapidAPI is published by Api Dojo. ### What does the Tasty API cost? Plans and quotas are set on the RapidAPI listing, so check there for current prices. ### Do I need an API key for Tiny Plates? Yes. Create a free account, make a key in the dashboard and send it as a bearer token. ## Try it [Create a free account](https://www.tinyplates.dev/sign-up) and follow the [quickstart](https://www.tinyplates.dev/docs/quickstart) to get a response in a couple of minutes. The [terms](https://www.tinyplates.dev/terms) say what you may cache and how to credit a recipe, and [the overview](https://www.tinyplates.dev/compare) lists the other recipe APIs. --- title: "Yummly API replacement — Tiny Plates" description: "The Yummly API closed in 2019 and Yummly itself in 2024. What Tiny Plates replaces, what it does not, and how to get started." url: "https://www.tinyplates.dev/compare/yummly" --- Tiny Plates / Compare # Yummly API replacement The Yummly API closed in 2019, and the app and website went offline in December 2024\. Here is what Tiny Plates covers and what it does not. ## What Yummly was Yummly was a recipe search and recommendation service. It opened a paid API in March 2013 and was bought by Whirlpool in May 2017\. The API closed in 2019, and the app and website were taken offline in December 2024. ## At a glance | Feature | Tiny Plates | Yummly | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- | | Status | Tiny Plates: Open, with a free plan. | Yummly: API closed on 30 September 2019\. App and website offline since December 2024. | | Price | Tiny Plates: A free plan with no credit card. Personal is $5 a month and Business $20, with extra requests at $1 per 1,000. | Yummly: Not for sale. | | Allowance | Tiny Plates: Free: 50 requests a day and 300 a week. Personal includes 5,000 requests a month and Business 20,000\. Enterprise on request. | Yummly: None. | | Search | Tiny Plates: By meaning as well as wording. | Yummly: Gone with the API. | ## What to know ### There is nothing to migrate The Yummly API has not answered since 2019, so there is no data to export and no endpoint to map. Moving means pointing your search and recipe calls at another API. ### Search and filters Tiny Plates searches by meaning, so “quick vegetarian dinner” works, and finds recipes from the ingredients you have. The “without” parameter leaves out recipes that contain any allergen you list. ### The recipe itself Every recipe comes back whole: parsed ingredients with canonical ids and numbered steps, with a link to the source. ## What Tiny Plates does not replace * The Yummly app. Recipe boxes and saved recipes went with it, and Tiny Plates is an API, not an app. * A corpus of Yummly’s size. We serve thousands of recipes. ## What you get instead * Recipe search by meaning, in English, Spanish and Swedish, and recipes from the ingredients you have. * Allergen filters: leave out recipes that contain any of the allergens you list. * The whole recipe in the response: parsed ingredients and numbered steps. * An MCP server, so an agent can use the same data. ## Questions ### Is the Yummly API still available? No. It closed on 30 September 2019, and Yummly’s app and website went offline in December 2024. ### What happened to Yummly? Whirlpool bought Yummly in May 2017 and took the app and website offline in December 2024. ### Does Tiny Plates replace the Yummly app? No. Tiny Plates is an API for developers, not a consumer app. ### Do I need an API key for Tiny Plates? Yes. Create a free account, make a key in the dashboard and send it as a bearer token. ## Try it [Create a free account](https://www.tinyplates.dev/sign-up) and follow the [quickstart](https://www.tinyplates.dev/docs/quickstart) to get a response in a couple of minutes. The [terms](https://www.tinyplates.dev/terms) say what you may cache and how to credit a recipe, and [the overview](https://www.tinyplates.dev/compare) lists the other recipe APIs.