Skip to main content

These are the docs for 0.25.0-beta, an older release.

See the current docs (0.25.1-beta) for what Norish does today.

API reference

Create an API key under Settings => User => API keys and send it as an x-api-key header or as Authorization: Bearer <key>. Replace https://norish.example.com in the examples with the address of your own server.

Base URL
https://norish.example.com/api/v1
Authentication
x-api-key: <key> or Authorization: Bearer <key>

Health

Check API health

GET/health

Reports API availability and verifies both the database connection and internal parser service are healthy.

Responses

The API, database, and parser service are healthy.

Response
{
"status": "ok",
"db": {
"status": "ok"
},
"versions": {
"root": "string",
"apps": {},
"packages": {},
"scraper": "string"
},
"parser": {
"status": "ok",
"recipeScrapersVersion": "string"
}
}

Example request

curl "https://norish.example.com/api/v1/health" \
-H "x-api-key: $NORISH_API_KEY"

Recipes

Get a recipe by ID

GET/recipes/{id}

Parameters

  • idstring (uuid)pathrequired

Responses

Successful response

Response
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"userId": "string",
"name": "string",
"description": "string",
"image": "string",
"url": "string",
"servings": 1,
"prepMinutes": 1,
"cookMinutes": 1,
"totalMinutes": 1,
"notes": "string",
"systemUsed": "metric",
"originalSystem": "metric",
"calories": 1,
"fat": "string",
"carbs": "string",
"protein": "string",
"originCountry": "string",
"originCountryName": "string",
"originRegion": "string",
"provenanceNote": "string",
"dishColor": "string",
"createdAt": "string",
"updatedAt": "string",
"categories": [
"Breakfast"
],
"version": 1,
"recipeIngredients": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"amount": 1,
"unit": "string",
"order": 1,
"systemUsed": "metric",
"version": 1,
"ingredientName": "string",
"ingredientId": "string"
}
],
"steps": [
{
"step": "string",
"systemUsed": "metric",
"order": 1,
"version": 1,
"images": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"image": "string",
"order": 0,
"version": 1
}
],
"stepIngredients": [
{
"ingredientOrder": 1,
"share": 1,
"order": 1
}
]
}
],
"tags": [
{
"name": "string",
"version": 1
}
],
"cuisines": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"version": 1
}
],
"author": {
"id": "string",
"name": "string",
"image": "string",
"version": 1
},
"images": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"image": "string",
"order": 0,
"generated": false,
"version": 1
}
],
"videos": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"video": "string",
"thumbnail": "string",
"duration": 1,
"order": 0,
"version": 1
}
],
"nutritionEstimate": {
"lines": [
{
"key": "string",
"calories": 1,
"fat": 1,
"carbs": 1,
"protein": 1
}
]
}
}

Example request

curl "https://norish.example.com/api/v1/recipes/{id}" \
-H "x-api-key: $NORISH_API_KEY"

List recipes

POST/recipes/search

Returns a paginated list of recipes. All filter fields are optional, so you can omit them to fetch the default recipe list.

Request body

  • cursorinteger

    Zero-based pagination offset. Defaults to 0.

    Default 0 · Min 0

  • limitinteger

    Maximum number of recipes to return. Defaults to 50.

    Default 50 · Min 1 · Max 200

  • searchstring

    Optional free-text search term.

  • searchFieldsstring[]

    Fields searched when search is provided. Defaults to title and ingredients.

    titledescriptioningredientsstepstags

    Default ["title","ingredients"]

  • tagsstring[]

    Optional tag filter.

  • categoriesstring[]

    Optional meal category filter.

    BreakfastLunchDinnerSnack
  • filterModestring

    How multi-value filters are combined. Defaults to OR.

    ANDOR

    Default "OR"

  • sortModestring

    Sort order for the returned recipes. Defaults to dateDesc.

    titleAsctitleDescdateAscdateDescnone

    Default "dateDesc"

  • minRatingnumber

    Optional minimum recipe rating.

    Min 1 · Max 5

  • maxCookingTimeinteger

    Optional maximum cooking time in minutes.

    Min 1

Responses

Successful response

Response
{
"recipes": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"userId": "string",
"name": "string",
"description": "string",
"image": "string",
"url": "string",
"servings": 1,
"prepMinutes": 1,
"cookMinutes": 1,
"totalMinutes": 1,
"notes": "string",
"calories": 1,
"originCountry": "string",
"createdAt": "string",
"updatedAt": "string",
"categories": [
"Breakfast"
],
"version": 1,
"tags": [
{
"name": "string",
"version": 1
}
],
"author": {
"id": "string",
"name": "string",
"image": "string",
"version": 1
},
"averageRating": 1,
"ratingCount": 1
}
],
"total": 0,
"nextCursor": 0
}

Example request

curl -X POST "https://norish.example.com/api/v1/recipes/search" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'

Create a recipe

POST/recipes

Creates a recipe directly from structured recipe data without parser transformation.

Request body

  • namestringrequired
  • descriptionstring | null
  • imagestring | null
  • urlstring | null
  • servingsinteger
  • prepMinutesinteger | null
  • cookMinutesinteger | null
  • totalMinutesinteger | null
  • notesstring | null
  • systemUsedstring
    metricus
  • originalSystemstring | null
    metricus
  • caloriesinteger | null
  • fatstring | null
  • carbsstring | null
  • proteinstring | null
  • originCountrystring | null
  • originCountryNamestring | null
  • originRegionstring | null
  • provenanceNotestring | null
  • dishColorstring | null
  • categoriesstring[]
    BreakfastLunchDinnerSnack
  • versioninteger
  • idstring (uuid)
  • recipeIngredientsobject[]
  • tagsobject[]
  • cuisinesstring (uuid)[]
  • stepsobject[]
  • imagesobject[]

    At most 10 items

  • videosobject[]

Responses

Successful response

Response
"6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"

Example request

curl -X POST "https://norish.example.com/api/v1/recipes" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string"
}'

Recipe Imports

Queue a recipe import from a URL

POST/recipes/import/url

Request body

  • urlstringrequired
  • forceAIboolean

Responses

Successful response

Response
{
"recipeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"status": "queued",
"recipe": {
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"userId": "string",
"name": "string",
"description": "string",
"image": "string",
"url": "string",
"servings": 1,
"prepMinutes": 1,
"cookMinutes": 1,
"totalMinutes": 1,
"notes": "string",
"calories": 1,
"originCountry": "string",
"createdAt": "string",
"updatedAt": "string",
"categories": [
"Breakfast"
],
"version": 1,
"tags": [
{
"name": "string",
"version": 1
}
],
"author": {
"id": "string",
"name": "string",
"image": "string",
"version": 1
},
"averageRating": 1,
"ratingCount": 1
}
}

Example request

curl -X POST "https://norish.example.com/api/v1/recipes/import/url" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "string"
}'

Queue a recipe import from pasted text

POST/recipes/import/paste

Request body

  • textstringrequired

    Pasted recipe text. Supports plain text, JSON-LD recipe objects/arrays/@graph payloads, and YAML recipe mappings/arrays. Each recipe is limited to 100,000 characters. When forcing AI only one recipe will be parsed. JSON-LD single example: {"@type":"Recipe","name":"Toast","recipeIngredient":["2 slices bread"],"recipeInstructions":["Toast bread"]} JSON-LD multi example: [{"@type":"Recipe",...},{"@type":"Recipe",...}] YAML single example: title: Toast\ningredients:\n - 2 slices bread\nsteps:\n - Toast bread YAML multi example: - title: Toast\n ingredients:\n - 2 slices bread\n steps:\n - Toast bread

    At least 1 characters

  • forceAIboolean

Responses

Successful response

Response
{
"recipeIds": [
"6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
]
}

Example request

curl -X POST "https://norish.example.com/api/v1/recipes/import/paste" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "string"
}'

Groceries

Get all groceries

GET/groceries

Responses

Successful response

Response
[
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"recipeIngredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"ingredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"unit": "string",
"amount": 1,
"purchaseAmount": 1,
"isDone": true,
"sortOrder": 1,
"version": 1,
"recurringGroceryId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
}
]

Example request

curl "https://norish.example.com/api/v1/groceries" \
-H "x-api-key: $NORISH_API_KEY"

Create a grocery

POST/groceries

Request body

  • namestring | nullrequired
  • unitstring | nullrequired
  • amountnumber | nullrequired
  • isDoneboolean

    Default false

  • storeIdstring (uuid) | null

Responses

Successful response

Response
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"recipeIngredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"ingredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"unit": "string",
"amount": 1,
"purchaseAmount": 1,
"isDone": true,
"sortOrder": 1,
"version": 1,
"recurringGroceryId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
}

Example request

curl -X POST "https://norish.example.com/api/v1/groceries" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"unit": "string",
"amount": 1
}'

Mark a grocery as done

PATCH/groceries/{id}/done

Send the grocery's current version from the list. If it no longer matches, nothing changes and the response has stale: true: fetch the list again and retry.

Parameters

  • idstring (uuid)pathrequired

Request body

  • versionintegerrequired

    Above 0

Responses

Successful response

Response
{
"grocery": {
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"recipeIngredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"ingredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"unit": "string",
"amount": 1,
"purchaseAmount": 1,
"isDone": true,
"sortOrder": 1,
"version": 1,
"recurringGroceryId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
},
"stale": true
}

Example request

curl -X PATCH "https://norish.example.com/api/v1/groceries/{id}/done" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 1
}'

Mark a grocery as not done

PATCH/groceries/{id}/undone

Send the grocery's current version from the list. If it no longer matches, nothing changes and the response has stale: true: fetch the list again and retry.

Parameters

  • idstring (uuid)pathrequired

Request body

  • versionintegerrequired

    Above 0

Responses

Successful response

Response
{
"grocery": {
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"recipeIngredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"ingredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"unit": "string",
"amount": 1,
"purchaseAmount": 1,
"isDone": true,
"sortOrder": 1,
"version": 1,
"recurringGroceryId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
},
"stale": true
}

Example request

curl -X PATCH "https://norish.example.com/api/v1/groceries/{id}/undone" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 1
}'

Delete a grocery

DELETE/groceries/{id}

Send the grocery's current version from the list. If it no longer matches, nothing changes and the response has stale: true: fetch the list again and retry.

Parameters

  • idstring (uuid)pathrequired
  • versionintegerqueryrequired

    Above 0

Responses

Successful response

Response
{
"success": true,
"stale": true
}

Example request

curl -X DELETE "https://norish.example.com/api/v1/groceries/{id}?version=1" \
-H "x-api-key: $NORISH_API_KEY"

Assign a grocery to a store

PATCH/groceries/{id}/store

Send the grocery's current version from the list; a stale version changes nothing and returns stale: true. A storeId of null removes the store. With savePreference (on by default) the same ingredient goes to this store next time.

Parameters

  • idstring (uuid)pathrequired

Request body

  • versionintegerrequired

    Above 0

  • storeIdstring (uuid) | nullrequired
  • savePreferenceboolean

    Default true

Responses

Successful response

Response
{
"grocery": {
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"recipeIngredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"ingredientId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"unit": "string",
"amount": 1,
"purchaseAmount": 1,
"isDone": true,
"sortOrder": 1,
"version": 1,
"recurringGroceryId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
},
"stale": true
}

Example request

curl -X PATCH "https://norish.example.com/api/v1/groceries/{id}/store" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
}'

Stores

List stores

GET/stores

Responses

Successful response

Response
[
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"userId": "string",
"name": "string",
"color": "string",
"website": "string",
"searchAddress": "string",
"sortOrder": 1,
"version": 1,
"aisles": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"sortOrder": 1,
"version": 1
}
]
}
]

Example request

curl "https://norish.example.com/api/v1/stores" \
-H "x-api-key: $NORISH_API_KEY"

Create a store

POST/stores

Request body

  • idstring (uuid)
  • namestringrequired

    At least 1 characters · At most 100 characters

  • colorstring
    primarysecondarysuccesswarningdangerslateskyviolet

    Default "primary"

  • websitestring (uri) | null
  • searchAddressstring | null

Responses

Successful response

Response
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"userId": "string",
"name": "string",
"color": "string",
"website": "string",
"searchAddress": "string",
"sortOrder": 1,
"version": 1,
"aisles": [
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"storeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"name": "string",
"sortOrder": 1,
"version": 1
}
]
}

Example request

curl -X POST "https://norish.example.com/api/v1/stores" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string"
}'

Planned Recipes

Get planned recipes for today

GET/planned-recipes/today

"Today" is the day in the server's timezone.

Responses

Successful response

Response
[
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"date": "string",
"slot": "Breakfast",
"sortOrder": 1,
"recipeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"version": 1,
"recipeName": "string",
"recipeImage": "string",
"servings": 1,
"calories": 1
}
]

Example request

curl "https://norish.example.com/api/v1/planned-recipes/today" \
-H "x-api-key: $NORISH_API_KEY"

Get planned recipes for the current week

GET/planned-recipes/week

The week runs Monday through Sunday in the server's timezone.

Responses

Successful response

Response
[
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"date": "string",
"slot": "Breakfast",
"sortOrder": 1,
"recipeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"version": 1,
"recipeName": "string",
"recipeImage": "string",
"servings": 1,
"calories": 1
}
]

Example request

curl "https://norish.example.com/api/v1/planned-recipes/week" \
-H "x-api-key: $NORISH_API_KEY"

Get planned recipes for the current month

GET/planned-recipes/month

The month is the calendar month in the server's timezone.

Responses

Successful response

Response
[
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"date": "string",
"slot": "Breakfast",
"sortOrder": 1,
"recipeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b",
"version": 1,
"recipeName": "string",
"recipeImage": "string",
"servings": 1,
"calories": 1
}
]

Example request

curl "https://norish.example.com/api/v1/planned-recipes/month" \
-H "x-api-key: $NORISH_API_KEY"

Create a planned recipe

POST/planned-recipes

Request body

  • idstring (uuid)
  • datestringrequired
  • slotstringrequired
    BreakfastLunchDinnerSnack
  • recipeIdstring (uuid)required

Responses

Successful response

Response
{
"id": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
}

Example request

curl -X POST "https://norish.example.com/api/v1/planned-recipes" \
-H "x-api-key: $NORISH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"date": "string",
"slot": "Breakfast",
"recipeId": "6f1c2a7e-8b5d-4c1e-9f2a-6d7b8c9e0a1b"
}'

Delete a planned recipe

DELETE/planned-recipes/{itemId}

Parameters

  • itemIdstring (uuid)pathrequired
  • versionintegerqueryrequired

    Above 0

Responses

Successful response

Response
{
"success": true,
"stale": true
}

Example request

curl -X DELETE "https://norish.example.com/api/v1/planned-recipes/{itemId}?version=1" \
-H "x-api-key: $NORISH_API_KEY"