---
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)
