API reference

Food

Recipes, collections, the meal plan, shopping lists, the pantry, suggestions and importing.

See Food. Food is personal: these routes take no organization. The plan, shopping lists and pantry are the household's, so everyone in it reads and changes the same ones. A key needs food:read (and food:write to change things) and acts for the person who made it. Public recipe links and the plan's calendar feed answer without a sign-in, at /v1/hooks/food.

GET /v1/hooks/food/r/:token

A recipe by its public link (no sign-in): the recipe without its owner's notes or rating. 404 once the link is off.

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.

Response 200

{
  recipe: {
    version: number
    createdAt: number
    updatedAt: number
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags: string[]
    ownerId: string
    steps: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    recipeId: string
    servings: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines: string[]
    courses: string[]
    claimedDiets: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons: "au" | "us"
    notes?: string
    rating?: number
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    images: {
      imageId: string
      versionId?: string
      mime?: string
      width?: number
      height?: number
      alt?: string
      url: string
      thumbUrl: string
    }[]
    nutrition: {
      perServing: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      total: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      coverage: number
      unmatched: string[]
    }
    allergens: string[]
    diets: string[]
    access: "owner" | "household" | "public"
    ownerName?: string
    publicUrl?: string
    cost?: {
      total: number
      perServing: number
      coverage: number
      priced: number
      measured: number
    }
  }
}

GET /v1/hooks/food/plan/:token

A household's meal plan as an iCalendar feed (<token>.ics, no sign-in): two weeks back to eight ahead, at meal times.

Auth: none

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.

Response 200 with no body.

GET /v1/me/food/settings

Your Food settings (measures, spoons, servings, diets, allergens, suggestions, Health logging, week start) and your household.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  settings: {
    measure: "metric" | "original" | "imperial"
    spoons: "au" | "us"
    defaultServings: number
    diets: string[]
    avoidAllergens: string[]
    weeknightMinutes?: number
    weatherSuggestions: boolean
    healthLogging: boolean
    calendar?: {
      orgId: string
      calendarId: string
    }
    weekStartsOn: number
    receiptMail?: {
      orgId: string
      mailboxId: string
      address: string
      since: number
      backfilledAt?: number
    }
    useSoonAlerts: boolean
    voiceControl: boolean
    weeklyBudget?: number
    timeZone?: string
  }
  home: {
    homeId: string
    name: string
    members: {
      userId: string
      name?: string
      role: "owner" | "member"
      joinedAt: number
    }[]
    createdAt: number
    receipts?: {
      token?: string
      autoAdd?: boolean
      confirmation?: {
        code?: string
        link?: string
        at: number
      }
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

PATCH /v1/me/food/settings

Changes the person's Food settings (only the fields given; null clears one).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
measure"original" | "metric" | "imperial"No
spoons"au" | "us"No
defaultServingsintegerNo1–50
diets[]Noup to 10 items
avoidAllergens[]Noup to 20 items
weeknightMinutesintegerNo10–240; can be null
weatherSuggestionsbooleanNo
healthLoggingbooleanNo
weekStartsOnintegerNo0–6
useSoonAlertsbooleanNo
voiceControlbooleanNo
weeklyBudgetnumberNo1–100000; can be null
timeZonestringNoup to 60 characters; matches ^[A-Za-z_]+(\/[A-Za-z0-9_+-]+){0,2}$

Also checked: Unknown fields are rejected.

Response 200

{
  settings: {
    measure: "metric" | "original" | "imperial"
    spoons: "au" | "us"
    defaultServings: number
    diets: string[]
    avoidAllergens: string[]
    weeknightMinutes?: number
    weatherSuggestions: boolean
    healthLogging: boolean
    calendar?: {
      orgId: string
      calendarId: string
    }
    weekStartsOn: number
    receiptMail?: {
      orgId: string
      mailboxId: string
      address: string
      since: number
      backfilledAt?: number
    }
    useSoonAlerts: boolean
    voiceControl: boolean
    weeklyBudget?: number
    timeZone?: string
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/home

Your household: its name and members (made, yours alone, the first time).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  home: {
    homeId: string
    name: string
    members: {
      userId: string
      name?: string
      role: "owner" | "member"
      joinedAt: number
    }[]
    createdAt: number
    receipts?: {
      token?: string
      autoAdd?: boolean
      confirmation?: {
        code?: string
        link?: string
        at: number
      }
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

PATCH /v1/me/food/home

Renames your household.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
namestringYes1–60 characters

Response 200

{
  home: {
    name: string
    homeId: string
    members: {
      userId: string
      name?: string
      role: "owner" | "member"
      joinedAt: number
    }[]
    createdAt: number
    receipts?: {
      token?: string
      autoAdd?: boolean
      confirmation?: {
        code?: string
        link?: string
        at: number
      }
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/home/invites

An invitation link into your household, good for a week.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Response 201

{
  invite: {
    code: string
    url: string
    expiresAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/home/invites/:code

What an invitation is for: the household's name, who invited you and how many are in it.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Path parameterDescription
:codeMirage invite code (8 letters and digits); under me/food a household invitation's code (from its link).

Response 200

{
  invite: {
    homeName: string
    invitedBy: string
    members: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/home/invites/:code/accept

Joins the household (your own waits for you; refused while yours has others in it).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:codeMirage invite code (8 letters and digits); under me/food a household invitation's code (from its link).

Response 200

{
  home: {
    homeId: string
    name: string
    members: {
      userId: string
      name?: string
      role: "owner" | "member"
      joinedAt: number
    }[]
    createdAt: number
    receipts?: {
      token?: string
      autoAdd?: boolean
      confirmation?: {
        code?: string
        link?: string
        at: number
      }
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/home/leave

Leaves the household, back to your own (its owner can't while others are in it).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Response 200

{
  home: {
    homeId: string
    name: string
    members: {
      userId: string
      name?: string
      role: "owner" | "member"
      joinedAt: number
    }[]
    createdAt: number
    receipts?: {
      token?: string
      autoAdd?: boolean
      confirmation?: {
        code?: string
        link?: string
        at: number
      }
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

DELETE /v1/me/food/home/members/:userId

Removes someone from your household (its owner only).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:userIdA member's user id (usr_…).

Response 200

{
  home: {
    members: {
      userId: string
      name?: string
      role: "owner" | "member"
      joinedAt: number
    }[]
    homeId: string
    name: string
    createdAt: number
    receipts?: {
      token?: string
      autoAdd?: boolean
      confirmation?: {
        code?: string
        link?: string
        at: number
      }
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/recipes

The person's recipes and their household's shared ones as cards, searched and filtered (limit: at most 1000, 200 by default).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredNotes
qstringNoup to 200 characters
cuisinestringNoup to 40 characters
coursestringNoup to 40 characters
dietstringNoup to 40 characters
tagstringNoup to 40 characters
withoutstringNoup to 200 characters
maxMinutesintegerNo1–10000; coerced from a string
ingredientstringNoup to 60 characters
favourites"1" | "true"No
collectionIdstringNoup to 40 characters
sort"recent" | "title" | "rating" | "cooked" | "quick"No
household"1" | "true" | "0" | "false"No
limitintegerNo1–1000; coerced from a string

Response 200

{
  recipes: {
    createdAt: number
    updatedAt: number
    title: string
    tags: string[]
    ownerId: string
    shared?: boolean
    favourite?: boolean
    recipeId: string
    servings: number
    totalMinutes?: number
    cuisines: string[]
    courses: string[]
    rating?: number
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    diets: string[]
    allergens: string[]
    kcalPerServing?: number
    ingredientIds: string[]
    amounts?: {
      [key: string]: {
        g?: number
        ml?: number
        each?: number
        minor?: true
      }
    }
    measuredLines?: number
    image?: {
      imageId: string
      versionId?: string
      mime?: string
      width?: number
      height?: number
      alt?: string
      url: string
      thumbUrl: string
    }
  }[]
  total: number
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/recipes

Adds a recipe. Ingredients and steps may be text (one ingredient per line; steps by paragraph), which Food reads; imageUrls are copied in by the worker.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
titleany JSONYes
descriptionany JSONNo
servingsintegerNo1–1000
yieldLabelany JSONNo
prepMinutesintegerNo0–43200
cookMinutesintegerNo0–43200
totalMinutesintegerNo0–43200
ingredientsobject[] | any JSONNoup to 150 items
stepsobject[] | any JSONNoup to 100 items
cuisines[]Noup to 5 items
courses[]Noup to 6 items
claimedDiets[]Noup to 10 items
tagsstring[]Noup to 30 items; each 1–40 characters, matches ^[\p{L}\p{N}][\p{L}\p{N} '&-]*$, trimmed, lowercased
difficulty"easy" | "medium" | "hard"Nocan be null
spoons"au" | "us"No
sourceobjectNo
source.kind"manual" | "web" | "photo" | "text" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"Yes
source.urlstringNoup to 2,000 characters; URL
source.nameany JSONNo
source.authorany JSONNo
notesstringNoup to 20,000 characters
ratingintegerNo1–5; can be null
favouritebooleanNo
householdbooleanNo
imagesobject[]Noup to 10 items
images[].imageIdstringYesup to 60 characters
images[].versionIdstringNoup to 60 characters
images[].mimestringNomatches ^image\/(jpeg|png|webp|gif)$
images[].widthintegerNo
images[].heightintegerNo
images[].altany JSONNo
imageUrlsstring[]Noup to 10 items; each up to 2,000 characters, URL

Also checked: Unknown fields are rejected.

Response 201

{
  recipe: {
    version: number
    createdAt: number
    updatedAt: number
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags: string[]
    ownerId: string
    steps: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    recipeId: string
    servings: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines: string[]
    courses: string[]
    claimedDiets: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons: "au" | "us"
    notes?: string
    rating?: number
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    images: {
      imageId: string
      versionId?: string
      mime?: string
      width?: number
      height?: number
      alt?: string
      url: string
      thumbUrl: string
    }[]
    nutrition: {
      perServing: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      total: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      coverage: number
      unmatched: string[]
    }
    allergens: string[]
    diets: string[]
    access: "owner" | "household" | "public"
    ownerName?: string
    publicUrl?: string
    cost?: {
      total: number
      perServing: number
      coverage: number
      priced: number
      measured: number
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/recipes/:recipeId

A recipe in full, with signed picture links, nutrition per serving, allergens, diets and your access (owner, household).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Path parameterDescription
:recipeIdA recipe's id (rcp_…).

Response 200

{
  recipe: {
    version: number
    createdAt: number
    updatedAt: number
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags: string[]
    ownerId: string
    steps: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    recipeId: string
    servings: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines: string[]
    courses: string[]
    claimedDiets: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons: "au" | "us"
    notes?: string
    rating?: number
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    images: {
      imageId: string
      versionId?: string
      mime?: string
      width?: number
      height?: number
      alt?: string
      url: string
      thumbUrl: string
    }[]
    nutrition: {
      perServing: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      total: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      coverage: number
      unmatched: string[]
    }
    allergens: string[]
    diets: string[]
    access: "owner" | "household" | "public"
    ownerName?: string
    publicUrl?: string
    cost?: {
      total: number
      perServing: number
      coverage: number
      priced: number
      measured: number
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

PATCH /v1/me/food/recipes/:recipeId

Changes a recipe of the person's (version: refused with 409 when it changed meanwhile).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:recipeIdA recipe's id (rcp_…).

Request body

FieldTypeRequiredNotes
titleany JSONNo
descriptionany JSONNo
servingsintegerNo1–1000
yieldLabelany JSONNo
prepMinutesintegerNo0–43200
cookMinutesintegerNo0–43200
totalMinutesintegerNo0–43200
ingredientsobject[] | any JSONNoup to 150 items
stepsobject[] | any JSONNoup to 100 items
cuisines[]Noup to 5 items
courses[]Noup to 6 items
claimedDiets[]Noup to 10 items
tagsstring[]Noup to 30 items; each 1–40 characters, matches ^[\p{L}\p{N}][\p{L}\p{N} '&-]*$, trimmed, lowercased
difficulty"easy" | "medium" | "hard"Nocan be null
spoons"au" | "us"No
sourceobjectNo
source.kind"manual" | "web" | "photo" | "text" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"Yes
source.urlstringNoup to 2,000 characters; URL
source.nameany JSONNo
source.authorany JSONNo
notesstringNoup to 20,000 characters
ratingintegerNo1–5; can be null
favouritebooleanNo
householdbooleanNo
imagesobject[]Noup to 10 items
images[].imageIdstringYesup to 60 characters
images[].versionIdstringNoup to 60 characters
images[].mimestringNomatches ^image\/(jpeg|png|webp|gif)$
images[].widthintegerNo
images[].heightintegerNo
images[].altany JSONNo
imageUrlsstring[]Noup to 10 items; each up to 2,000 characters, URL
versionintegerNo≥ 0

Also checked: Unknown fields are rejected. Unknown fields are rejected.

Response 200

{
  recipe: {
    version: number
    createdAt: number
    updatedAt: number
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags: string[]
    ownerId: string
    steps: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    recipeId: string
    servings: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines: string[]
    courses: string[]
    claimedDiets: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons: "au" | "us"
    notes?: string
    rating?: number
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    images: {
      imageId: string
      versionId?: string
      mime?: string
      width?: number
      height?: number
      alt?: string
      url: string
      thumbUrl: string
    }[]
    nutrition: {
      perServing: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      total: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      coverage: number
      unmatched: string[]
    }
    allergens: string[]
    diets: string[]
    access: "owner" | "household" | "public"
    ownerName?: string
    publicUrl?: string
    cost?: {
      total: number
      perServing: number
      coverage: number
      priced: number
      measured: number
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

DELETE /v1/me/food/recipes/:recipeId

Deletes a recipe of yours, its pictures (freeing their storage) and its public link.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:recipeIdA recipe's id (rcp_…).

Response 200

{
  recipeId: string
  deleted: boolean
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/recipes/:recipeId/copy

Copies a recipe your household shares into your own recipes (pictures copied into your storage).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:recipeIdA recipe's id (rcp_…).

Response 201

{
  recipe: {
    version: number
    createdAt: number
    updatedAt: number
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags: string[]
    ownerId: string
    steps: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    recipeId: string
    servings: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines: string[]
    courses: string[]
    claimedDiets: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons: "au" | "us"
    notes?: string
    rating?: number
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    images: {
      imageId: string
      versionId?: string
      mime?: string
      width?: number
      height?: number
      alt?: string
      url: string
      thumbUrl: string
    }[]
    nutrition: {
      perServing: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      total: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      coverage: number
      unmatched: string[]
    }
    allergens: string[]
    diets: string[]
    access: "owner" | "household" | "public"
    ownerName?: string
    publicUrl?: string
    cost?: {
      total: number
      perServing: number
      coverage: number
      priced: number
      measured: number
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/recipes/:recipeId/cook

Logs that the person cooked it, with a rating and note; logToHealth logs a serving to Health's nutrition (when they turned it on).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:recipeIdA recipe's id (rcp_…).

Request body

FieldTypeRequiredNotes
servingsintegerNo1–100
ratingintegerNo1–5
noteany JSONNo
atintegerNo
logToHealthbooleanNo
leftoversobjectNo
leftovers.portionsintegerYes1–50
leftovers.place"fridge" | "freezer"Yes
leftovers.useBystringNomatches ^\d{4}-\d{2}-\d{2}$

Also checked: Unknown fields are rejected.

Response 201

{
  leftovers?: {
    itemId: string
    name: string
    ingredientId?: string
    quantity?: number
    unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
    place: "fridge" | "freezer" | "pantry"
    useBy?: string
    addedBy: string
    addedAt: number
    source?: "photo" | "manual" | "receipt" | "leftovers" | "barcode"
    barcode?: string
    leftover?: {
      recipeId: string
      title: string
      portions: number
      cookedOn: string
    }
  }
  health?: {
    logged: boolean
    error?: string
  }
  cook: {
    cookId: string
    recipeId: string
    title: string
    userId: string
    at: number
    servings?: number
    rating?: number
    note?: string
    loggedToHealth?: boolean
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

Turns the recipe's public link on (a new link each time) or off.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:recipeIdA recipe's id (rcp_…).

Request body

FieldTypeRequiredNotes
onbooleanYes

Response 200

{
  recipeId: string
  publicUrl: null | string
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/recipes/:recipeId/notes

Saves the recipe as a Notes page in one of the person's orgs (where they can write Notes).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Path parameterDescription
:recipeIdA recipe's id (rcp_…).

Request body

FieldTypeRequiredNotes
orgIdstringYes1–64 characters
parentIdstringNoup to 64 characters

Response 201

{
  page: {
    orgId: string
    pageId: string
    title: string
  }
}

Errors

StatusMessage
400Parent page not found.
400The parent page is in the trash.
400Unknown property.
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.
403You can't add pages to Notes in that organization.
404Page not found
409This page is in the trash. Restore it to edit.
413Pages can be up to 1 MB.

POST /v1/me/food/public/:token/copy

Copies a recipe shared by public link into your own recipes.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:tokenA secret from a link: an issue automation rule's incoming-webhook token (shown once when issued), a map's share link, a notification recipient's confirm and unsubscribe link, a Drive public link (/l/<token>), or a Mirage interaction's token (itk_…, sent with the interaction, good for 15 minutes), or the token in the link to a file of a message Mirage sent to Discord, or a Marketing link's sealed token (a tracked click, the open pixel, unsubscribe and the preference centre, a double opt-in confirmation); or a Food recipe's public link (/r/<token>) or a household's calendar feed.

Response 201

{
  recipe: {
    version: number
    createdAt: number
    updatedAt: number
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags: string[]
    ownerId: string
    steps: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    recipeId: string
    servings: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines: string[]
    courses: string[]
    claimedDiets: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons: "au" | "us"
    notes?: string
    rating?: number
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    images: {
      imageId: string
      versionId?: string
      mime?: string
      width?: number
      height?: number
      alt?: string
      url: string
      thumbUrl: string
    }[]
    nutrition: {
      perServing: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      total: {
        kj: number
        kcal: number
        protein: number
        fat: number
        saturatedFat: number
        carbs: number
        sugars: number
        fibre: number
        sodium: number
      }
      coverage: number
      unmatched: string[]
    }
    allergens: string[]
    diets: string[]
    access: "owner" | "household" | "public"
    ownerName?: string
    publicUrl?: string
    cost?: {
      total: number
      perServing: number
      coverage: number
      priced: number
      measured: number
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/history

What you've cooked, newest first, with ratings and notes (limit, 100 by default).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredDefaultNotes
limitstringNo100

Response 200

{
  cooked: {
    cookId: string
    recipeId: string
    title: string
    userId: string
    at: number
    servings?: number
    rating?: number
    note?: string
    loggedToHealth?: boolean
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/images

Keeps a picture (base64 JPEG, PNG, WebP or GIF, at most 8 MB) in the person's Food drive, metadata removed; use the answer in a recipe's images.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body (up to 10 MB)

FieldTypeRequiredNotes
datastringYes10–12,000,000 characters
namestringNoup to 100 characters
altstringNoup to 300 characters

Response 201

{
  image?: {
    imageId: string
    versionId?: string
    mime?: string
    width?: number
    height?: number
    alt?: string
    url: string
    thumbUrl: string
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.
413That's too large. Send pictures of at most 8 MB, four at a time.

GET /v1/me/food/collections

Your collections, with their recipes in order and their groups.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  collections: {
    collectionId: string
    ownerId: string
    name: string
    description?: string
    recipeIds: string[]
    groups?: {
      name: string
      recipeIds: string[]
    }[]
    coverRecipeId?: string
    createdAt: number
    updatedAt: number
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/collections

A new collection, optionally with recipes and named groups.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
nameany JSONYes
descriptionany JSONNo
recipeIdsstring[]Noup to 2,000 items; each up to 40 characters
groupsobject[]Noup to 50 items
groups[].nameany JSONYes
groups[].recipeIdsstring[]Yesup to 2,000 items; each up to 40 characters

Also checked: Unknown fields are rejected.

Response 201

{
  collection: {
    collectionId: string
    ownerId: string
    name: string
    description?: string
    recipeIds: string[]
    groups?: {
      name: string
      recipeIds: string[]
    }[]
    coverRecipeId?: string
    createdAt: number
    updatedAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

PATCH /v1/me/food/collections/:collectionId

Renames a collection or changes its recipes (add, remove, or the whole recipeIds in order).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:collectionIdA Food collection's id (fcl_…).

Request body

FieldTypeRequiredNotes
nameany JSONNo
descriptionany JSONNo
recipeIdsstring[]Noup to 2,000 items; each up to 40 characters
groupsobject[]Noup to 50 items
groups[].nameany JSONYes
groups[].recipeIdsstring[]Yesup to 2,000 items; each up to 40 characters
addstring[]Noup to 500 items; each up to 40 characters
removestring[]Noup to 500 items; each up to 40 characters

Also checked: Unknown fields are rejected.

Response 200

{
  collection: {
    collectionId: string
    ownerId: string
    name: string
    description?: string
    recipeIds: string[]
    groups?: {
      name: string
      recipeIds: string[]
    }[]
    coverRecipeId?: string
    createdAt: number
    updatedAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

DELETE /v1/me/food/collections/:collectionId

Deletes a collection (its recipes stay).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:collectionIdA Food collection's id (fcl_…).

Response 200

{
  collectionId: string
  deleted: boolean
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/plan

The household's meals between two days (at most 92).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredNotes
fromstringYesmatches ^\d{4}-\d{2}-\d{2}$
tostringYesmatches ^\d{4}-\d{2}-\d{2}$

Response 200

{
  entries: {
    leftover?: {
      itemId: string
      cookedOn: string
    }
    entryId: string
    homeId: string
    day: string
    meal: "breakfast" | "lunch" | "dinner" | "snack"
    recipeId?: string
    title: string
    servings?: number
    note?: string
    addedBy: string
    calendarEventId?: string
    cooked?: boolean
    createdAt: number
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/plan

Puts a meal on the household's plan: a recipe, or a note ("Leftovers").

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
daystringYesmatches ^\d{4}-\d{2}-\d{2}$
meal``Yes
recipeIdstringNoup to 40 characters
titleany JSONNo
servingsintegerNo1–100
noteany JSONNo
leftoverItemIdstringNoup to 40 characters

Also checked: Unknown fields are rejected. Choose a recipe or write what's on.

Response 201

{
  entry: {
    leftover?: {
      itemId: string
      cookedOn: string
    }
    entryId: string
    homeId: string
    day: string
    meal: "breakfast" | "lunch" | "dinner" | "snack"
    recipeId?: string
    title: string
    servings?: number
    note?: string
    addedBy: string
    calendarEventId?: string
    cooked?: boolean
    createdAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

PATCH /v1/me/food/plan/:entryId

Moves or changes a meal (from: the day it's on now, which saves a lookup).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:entryIdA meal on the plan (fpe_…).

Request body

FieldTypeRequiredNotes
daystringNomatches ^\d{4}-\d{2}-\d{2}$
meal"breakfast" | "lunch" | "dinner" | "snack"No
recipeIdstringNoup to 40 characters
titlestringNoup to 200 characters
servingsintegerNo1–100
notestringNoup to 500 characters
cookedbooleanNo
fromstringNomatches ^\d{4}-\d{2}-\d{2}$

Also checked: Unknown fields are rejected.

Response 200

{
  entry: {
    leftover?: {
      itemId: string
      cookedOn: string
    }
    entryId: string
    homeId: string
    day: string
    meal: "breakfast" | "lunch" | "dinner" | "snack"
    recipeId?: string
    title: string
    servings?: number
    note?: string
    addedBy: string
    calendarEventId?: string
    cooked?: boolean
    createdAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

DELETE /v1/me/food/plan/:entryId

Takes a meal off the plan (day: the day it's on, which saves a lookup).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:entryIdA meal on the plan (fpe_…).
Query parameterTypeRequiredNotes
daystringNo

Response 200

{
  entry: {
    leftover?: {
      itemId: string
      cookedOn: string
    }
    entryId: string
    homeId: string
    day: string
    meal: "breakfast" | "lunch" | "dinner" | "snack"
    recipeId?: string
    title: string
    servings?: number
    note?: string
    addedBy: string
    calendarEventId?: string
    cooked?: boolean
    createdAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/plan/feed

The household's private calendar feed link (url, and webcal for calendar apps).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  feed: {
    url: string
    webcal: string
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/plan/feed/rotate

Replaces the calendar feed link; the old one stops working.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Response 200

{
  feed: {
    url: string
    webcal: string
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/plan/suggest

Proposes (or with apply, plans) meals for the days ahead from the suggestions.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
fromstringNomatches ^\d{4}-\d{2}-\d{2}$
daysintegerNo1–14
meal"breakfast" | "lunch" | "dinner" | "snack"No
maxMinutesintegerNo5–600
dietsstring[]Noup to 10 items; each up to 40 characters
budgetnumberNo1–100000
applybooleanNo

Also checked: Unknown fields are rejected.

Response 200

{
  budget?: number
  cost?: {
    total: number
    priced: number
    nights: number
  }
  from: string
  days: number
  meal: "breakfast" | "lunch" | "dinner" | "snack"
  applied: boolean
  planned: {
    cost?: number
    day: string
    meal: "breakfast" | "lunch" | "dinner" | "snack"
    recipeId: string
    title: string
    totalMinutes?: number
    reasons: string[]
  }[]
  skippedDays: string[]
  unfilled: string[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/plan/calendar

Puts planned meals on a Mail calendar of the person's (events at meal times, linking back).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
orgIdstringYes1–64 characters
mailboxIdstringYes1–64 characters
calendarIdstringYes1–64 characters
fromstringYesmatches ^\d{4}-\d{2}-\d{2}$
tostringYesmatches ^\d{4}-\d{2}-\d{2}$
timeZonestringYes1–64 characters

Response 200

{
  added: number
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.
403You can't add events to calendars in that organization.
404Mailbox not found

GET /v1/me/food/lists

The household's shopping lists, most recently changed first.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  lists: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/lists

A new list: empty, from the plan between two days, or from recipes at given servings (merged by ingredient, by aisle, without the pantry).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
namestringNoup to 100 characters
fromPlanobjectNo
fromPlan.fromstringYesmatches ^\d{4}-\d{2}-\d{2}$
fromPlan.tostringYesmatches ^\d{4}-\d{2}-\d{2}$
fromRecipesobject[]Noup to 50 items
fromRecipes[].recipeIdstringYesup to 40 characters
fromRecipes[].servingsintegerNo1–100
skipPantrybooleanNo
withStaplesbooleanNo

Also checked: Unknown fields are rejected.

Response 201

{
  list: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/lists/:listId

A shopping list with its items (aisle, amount, ticked, the recipes they're for).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Path parameterDescription
:listIdSaved map id (mls_…); under marketing a list (mkl_…); under me/food a shopping list (fls_…).

Response 200

{
  list: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }
  prices: {
    [key: string]: {
      day: string
      paid: number
      storeName: string
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

PATCH /v1/me/food/lists/:listId

Renames a list.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:listIdSaved map id (mls_…); under marketing a list (mkl_…); under me/food a shopping list (fls_…).

Request body

FieldTypeRequiredNotes
namestringYes1–100 characters

Response 200

{
  list: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

DELETE /v1/me/food/lists/:listId

Deletes a list.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:listIdSaved map id (mls_…); under marketing a list (mkl_…); under me/food a shopping list (fls_…).

Response 200

{
  listId: string
  deleted: boolean
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/lists/:listId/items

Adds items to a list (their aisle from the ingredient when not given).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:listIdSaved map id (mls_…); under marketing a list (mkl_…); under me/food a shopping list (fls_…).

Request body

FieldTypeRequiredNotes
itemsobject[]Yes1–100 items
items[].nameany JSONYes
items[].quantitynumberNo0–100000
items[].unit``No
items[].amountany JSONNo
items[].aisle``No
items[].noteany JSONNo

Also checked: Unknown fields are rejected.

Response 201

{
  list: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/lists/:listId/recipes

Adds recipes' ingredients to a list (merged with what's on it).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:listIdSaved map id (mls_…); under marketing a list (mkl_…); under me/food a shopping list (fls_…).

Request body

FieldTypeRequiredNotes
recipesobject[]Yes1–50 items
recipes[].recipeIdstringYesup to 40 characters
recipes[].servingsintegerNo1–100
skipPantrybooleanNo

Also checked: Unknown fields are rejected.

Response 200

{
  list: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

PATCH /v1/me/food/lists/:listId/items/:itemId

Ticks an item (checked) or changes it; two people ticking at once both land.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:listIdSaved map id (mls_…); under marketing a list (mkl_…); under me/food a shopping list (fls_…).
:itemIdDrive file (fil_…) or folder (fld_…) id, or a drive id for its top folder; under me/food a shopping list item (fli_…) or something in the pantry (fpn_…).

Request body

FieldTypeRequiredNotes
nameany JSONNo
quantitynumberNo0–100000
unit``No
amountany JSONNo
aisle``No
noteany JSONNo
checkedbooleanNo

Also checked: Unknown fields are rejected. Unknown fields are rejected.

Response 200

{
  list: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/lists/:listId/items/remove

Removes items by id, or every ticked one ({ "checked": true }).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:listIdSaved map id (mls_…); under marketing a list (mkl_…); under me/food a shopping list (fls_…).

Response 200

{
  list: {
    listId: string
    homeId: string
    name: string
    items: {
      itemId: string
      name: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      amount?: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
      ingredientId?: string
      note?: string
      checked: boolean
      forRecipes?: string[]
      addedBy: string
      addedAt: number
      checkedBy?: string
    }[]
    createdAt: number
    updatedAt: number
    version: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/pantry

What the household has in, soonest use-by first.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  items: {
    itemId: string
    name: string
    ingredientId?: string
    quantity?: number
    unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
    place: "fridge" | "freezer" | "pantry"
    useBy?: string
    addedBy: string
    addedAt: number
    source?: "photo" | "manual" | "receipt" | "leftovers" | "barcode"
    barcode?: string
    leftover?: {
      recipeId: string
      title: string
      portions: number
      cookedOn: string
    }
  }[]
  prices: {
    [key: string]: {
      day: string
      paid: number
      storeName: string
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/pantry

Adds things to the household's pantry, fridge or freezer: placed by kind and given an estimated use-by unless given; merged into the same thing already there unless merge is false.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
itemsobject[]Yes1–100 items
items[].nameany JSONYes
items[].quantitynumberNo0–100000
items[].unit``No
items[].place"pantry" | "fridge" | "freezer"No
items[].useBystringNomatches ^\d{4}-\d{2}-\d{2}$; can be null
items[].ingredientIdstringNoup to 60 characters
items[].source"manual" | "barcode" | "photo" | "receipt" | "leftovers"No
items[].barcodestringNomatches ^\d{8,14}$
items[].mergebooleanNo

Also checked: Unknown fields are rejected.

Response 201

{
  items: {
    itemId: string
    name: string
    ingredientId?: string
    quantity?: number
    unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
    place: "fridge" | "freezer" | "pantry"
    useBy?: string
    addedBy: string
    addedAt: number
    source?: "photo" | "manual" | "receipt" | "leftovers" | "barcode"
    barcode?: string
    leftover?: {
      recipeId: string
      title: string
      portions: number
      cookedOn: string
    }
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/pantry/use-soon

What needs using soon (within days, 3 by default) and the recipes that use the most of it.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredNotes
daysintegerNo1–14; coerced from a string
todaystringNomatches ^\d{4}-\d{2}-\d{2}$

Response 200

{
  items: {
    itemId: string
    name: string
    ingredientId?: string
    quantity?: number
    unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
    place: "fridge" | "freezer" | "pantry"
    useBy?: string
    addedBy: string
    addedAt: number
    source?: "photo" | "manual" | "receipt" | "leftovers" | "barcode"
    barcode?: string
    leftover?: {
      recipeId: string
      title: string
      portions: number
      cookedOn: string
    }
  }[]
  recipes: {
    recipe: {
      createdAt: number
      updatedAt: number
      title: string
      tags: string[]
      ownerId: string
      shared?: boolean
      favourite?: boolean
      recipeId: string
      servings: number
      totalMinutes?: number
      cuisines: string[]
      courses: string[]
      rating?: number
      household: boolean
      cookedCount: number
      lastCookedAt?: number
      diets: string[]
      allergens: string[]
      kcalPerServing?: number
      ingredientIds: string[]
      amounts?: {
        [key: string]: {
          g?: number
          ml?: number
          each?: number
          minor?: true
        }
      }
      measuredLines?: number
      image?: {
        imageId: string
        versionId?: string
        mime?: string
        width?: number
        height?: number
        alt?: string
        url: string
        thumbUrl: string
      }
    }
    uses: string[]
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

GET /v1/me/food/pantry/barcodes/:code

What a barcode is (the household's own answer, else Open Food Facts), as a pantry item to check; found: false when nobody knows it.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:codeMirage invite code (8 letters and digits); under me/food a household invitation's code (from its link).
Query parameterTypeRequiredNotes
todaystringNomatches ^\d{4}-\d{2}-\d{2}$

Response 200

{
  code: string
  found: true
  source: "household"
  item: {
    name: string
    ingredientId?: string
    quantity?: number
    unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
    place: "fridge" | "freezer" | "pantry"
    useBy?: string
    barcode?: string
    brand?: string
    mergeInto?: {
      itemId: string
      name: string
    }
  }
} | {
  code: string
  found: false
  source?: undefined
  item?: undefined
} | {
  code: string
  found: true
  source: "openfoodfacts"
  item: {
    name: string
    ingredientId?: string
    quantity?: number
    unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
    place: "fridge" | "freezer" | "pantry"
    useBy?: string
    barcode?: string
    brand?: string
    mergeInto?: {
      itemId: string
      name: string
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

PUT /v1/me/food/pantry/barcodes/:code

The household's own answer for a barcode (one nobody knew, or a correction).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:codeMirage invite code (8 letters and digits); under me/food a household invitation's code (from its link).

Request body

FieldTypeRequiredNotes
namestringYes1–120 characters; trimmed
ingredientIdstringNoup to 60 characters
quantitynumberNo0–100000
unit"g" | "kg" | "ml" | "l"No

Also checked: Unknown fields are rejected.

Response 200

{
  barcode: {
    ingredientId?: string
    code: string
    name: string
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/pantry/scans

Photos of a shelf, the fridge or a bench of shopping (base64, up to four), read by the model into items to check; poll the scan. Counts against the daily photo readings.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body (up to 10 MB)

FieldTypeRequiredNotes
photosstring[]Yes1–4 items; each 10–12,000,000 characters

Response 202

{
  scan: {
    createdAt: number
    error?: string
    items?: {
      name: string
      ingredientId?: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      place: "fridge" | "freezer" | "pantry"
      useBy?: string
      barcode?: string
      brand?: string
      mergeInto?: {
        itemId: string
        name: string
      }
    }[]
    scanId: string
    status: "done" | "failed" | "running"
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.
413That's too large. Send pictures of at most 8 MB, four at a time.

GET /v1/me/food/pantry/scans/:scanId

A pantry photo being read: running, then done with the items to check (placed, with estimated use-bys and what each would add to), or failed.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Path parameterDescription
:scanIdA pantry photo being read (fsc_…).

Response 200

{
  scan: {
    createdAt: number
    error?: string
    items?: {
      name: string
      ingredientId?: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      place: "fridge" | "freezer" | "pantry"
      useBy?: string
      barcode?: string
      brand?: string
      mergeInto?: {
        itemId: string
        name: string
      }
    }[]
    scanId: string
    status: "done" | "failed" | "running"
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

PATCH /v1/me/food/pantry/:itemId

Changes something in the pantry (useBy: null clears its date).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:itemIdDrive file (fil_…) or folder (fld_…) id, or a drive id for its top folder; under me/food a shopping list item (fli_…) or something in the pantry (fpn_…).

Request body

FieldTypeRequiredNotes
nameany JSONNo
quantitynumberNo0–100000
unit``No
place"pantry" | "fridge" | "freezer"No
useBystringNomatches ^\d{4}-\d{2}-\d{2}$; can be null

Also checked: Unknown fields are rejected.

Response 200

{
  item: {
    itemId: string
    name: string
    ingredientId?: string
    quantity?: number
    unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
    place: "fridge" | "freezer" | "pantry"
    useBy?: string
    addedBy: string
    addedAt: number
    source?: "photo" | "manual" | "receipt" | "leftovers" | "barcode"
    barcode?: string
    leftover?: {
      recipeId: string
      title: string
      portions: number
      cookedOn: string
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/pantry/remove

Takes things out of the pantry (used up).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
itemIdsstring[]Yes1–500 items; each 1–60 characters

Response 200

{
  removed: number
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/cookable

"What can I cook?": the person's and household's recipes by how much the pantry covers, with what's missing.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  recipes: {
    recipe: {
      createdAt: number
      updatedAt: number
      title: string
      tags: string[]
      ownerId: string
      shared?: boolean
      favourite?: boolean
      recipeId: string
      servings: number
      totalMinutes?: number
      cuisines: string[]
      courses: string[]
      rating?: number
      household: boolean
      cookedCount: number
      lastCookedAt?: number
      diets: string[]
      allergens: string[]
      kcalPerServing?: number
      ingredientIds: string[]
      amounts?: {
        [key: string]: {
          g?: number
          ml?: number
          each?: number
          minor?: true
        }
      }
      measuredLines?: number
      image?: {
        imageId: string
        versionId?: string
        mime?: string
        width?: number
        height?: number
        alt?: string
        url: string
        thumbUrl: string
      }
    }
    have: number
    need: number
    missing: string[]
    expiring: string[]
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

GET /v1/me/food/receipts

The household's grocery receipts, newest purchase first (status: new, added or dismissed).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredNotes
status"new" | "added" | "dismissed"No

Response 200

{
  receipts: {
    receiptId: string
    store: string
    storeName: string
    purchasedOn: string
    total?: number
    lines: {
      id: string
      text: string
      name: string
      ingredientId?: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      price?: number
      detail?: string
      food: boolean
      place?: "fridge" | "freezer" | "pantry"
      useBy?: string
    }[]
    status: "added" | "dismissed" | "new"
    via: "upload" | "mail" | "forward"
    read: "model" | "rules"
    userId?: string
    createdAt: number
    addedAt?: number
    addedBy?: string
    added?: number
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

GET /v1/me/food/receipts/settings

Receipts settings: the household's forwarding address (when made), whether receipts go straight in, Gmail's last confirmation, and the person's Cactive Mail link.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  stores: {
    id: string
    name: string
  }[]
  mail?: {
    orgId: string
    mailboxId: string
    address: string
    since: number
    backfilledAt?: number
  }
  confirmation?: {
    code?: string
    link?: string
    at: number
  }
  autoAdd: boolean
  forwarding?: string
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

PATCH /v1/me/food/receipts/settings

Whether the household's new receipts go straight into the pantry (autoAdd) or wait for review.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
autoAddbooleanYes

Also checked: Unknown fields are rejected.

Response 200

{
  home: {
    receipts: {
      autoAdd: boolean
      token?: string
      confirmation?: {
        code?: string
        link?: string
        at: number
      }
    }
    homeId: string
    name: string
    members: {
      userId: string
      name?: string
      role: "owner" | "member"
      joinedAt: number
    }[]
    createdAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/receipts/forwarding

Makes the household's private forwarding address (or a new one with rotate: the old one stops working).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
rotatebooleanNo

Also checked: Unknown fields are rejected.

Response 200

{
  address: string
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

PUT /v1/me/food/receipts/mail

Turns on grocery receipts from one of the person's Cactive Mail mailboxes (they must be a member): Food then reads only mail from the stores' e-receipt senders there.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
orgIdstringYes1–64 characters
mailboxIdstringYes1–64 characters

Also checked: Unknown fields are rejected.

Response 200

{
  settings: {
    measure: "metric" | "original" | "imperial"
    spoons: "au" | "us"
    defaultServings: number
    diets: string[]
    avoidAllergens: string[]
    weeknightMinutes?: number
    weatherSuggestions: boolean
    healthLogging: boolean
    calendar?: {
      orgId: string
      calendarId: string
    }
    weekStartsOn: number
    receiptMail?: {
      orgId: string
      mailboxId: string
      address: string
      since: number
      backfilledAt?: number
    }
    useSoonAlerts: boolean
    voiceControl: boolean
    weeklyBudget?: number
    timeZone?: string
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.
403You can't read mail in that organization.
404Mailbox not found

DELETE /v1/me/food/receipts/mail

Stops reading grocery receipts from the person's Cactive Mail; receipts already read stay.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Response 200

{
  settings: {
    measure: "metric" | "original" | "imperial"
    spoons: "au" | "us"
    defaultServings: number
    diets: string[]
    avoidAllergens: string[]
    weeknightMinutes?: number
    weatherSuggestions: boolean
    healthLogging: boolean
    calendar?: {
      orgId: string
      calendarId: string
    }
    weekStartsOn: number
    receiptMail?: {
      orgId: string
      mailboxId: string
      address: string
      since: number
      backfilledAt?: number
    }
    useSoonAlerts: boolean
    voiceControl: boolean
    weeklyBudget?: number
    timeZone?: string
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/receipts/mail/backfill

"Check the last 30 days" (once): the linked mailbox's mail from the stores' e-receipt senders, read for receipts.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Response 202

{
  queued: number
}

Errors

StatusMessage
400Turn on receipts from Cactive Mail first.
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/receipts/:receiptId

One receipt (decrypted): the store, the day, the total and each line with its price, amount, place and estimated use-by.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Path parameterDescription
:receiptIdA grocery receipt (frc_…).

Response 200

{
  receipt: {
    receiptId: string
    store: string
    storeName: string
    purchasedOn: string
    total?: number
    lines: {
      id: string
      text: string
      name: string
      ingredientId?: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      price?: number
      detail?: string
      food: boolean
      place?: "fridge" | "freezer" | "pantry"
      useBy?: string
    }[]
    status: "added" | "dismissed" | "new"
    via: "upload" | "mail" | "forward"
    read: "model" | "rules"
    userId?: string
    createdAt: number
    addedAt?: number
    addedBy?: string
    added?: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/receipts/:receiptId/add

Puts a receipt into the pantry: its food lines, or the lines as ticked and changed (merged into what's there).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:receiptIdA grocery receipt (frc_…).

Request body

FieldTypeRequiredNotes
linesobject[]Noup to 500 items
lines[].idstringYesup to 40 characters
lines[].includebooleanNo
lines[].namestringNo1–200 characters; trimmed
lines[].quantitynumberNo0–100000; can be null
lines[].unitany JSONNocan be null
lines[].place"pantry" | "fridge" | "freezer"No
lines[].useBystringNomatches ^\d{4}-\d{2}-\d{2}$; can be null
lines[].mergebooleanNo

Also checked: Unknown fields are rejected.

Response 200

{
  receipt: {
    receiptId: string
    store: string
    storeName: string
    purchasedOn: string
    total?: number
    lines: {
      id: string
      text: string
      name: string
      ingredientId?: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      price?: number
      detail?: string
      food: boolean
      place?: "fridge" | "freezer" | "pantry"
      useBy?: string
    }[]
    status: "added" | "dismissed" | "new"
    via: "upload" | "mail" | "forward"
    read: "model" | "rules"
    userId?: string
    createdAt: number
    addedAt?: number
    addedBy?: string
    added?: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/receipts/:receiptId/dismiss

Leaves a receipt out of the pantry (it still counts in spending).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:receiptIdA grocery receipt (frc_…).

Response 200

{
  receipt: {
    status: "dismissed"
    receiptId: string
    store: string
    storeName: string
    purchasedOn: string
    total?: number
    lines: {
      id: string
      text: string
      name: string
      ingredientId?: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      price?: number
      detail?: string
      food: boolean
      place?: "fridge" | "freezer" | "pantry"
      useBy?: string
    }[]
    via: "upload" | "mail" | "forward"
    read: "model" | "rules"
    userId?: string
    createdAt: number
    addedAt?: number
    addedBy?: string
    added?: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

DELETE /v1/me/food/receipts

Deletes the household's receipts and prices (and the key they're sealed with).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Response 200

{
  removed: number
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/spending

Grocery spending by month from the household's receipts (months: 1 to 24, 6 by default).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredNotes
monthsintegerNo1–24; coerced from a string
todaystringNomatches ^\d{4}-\d{2}-\d{2}$

Response 200

{
  months: {
    month: string
    total: number
    receipts: number
    stores: {
      name: string
      total: number
    }[]
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/delete-all

Deletes all the person's Food data (call again while done is false): see docs/food/README.md → Privacy.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Response 200

{
  done: boolean
  remaining: number
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/suggestions

Ideas from the person's recipes with why (ratings, history, the season, the pantry, the weather when turned on), within their diets and allergens.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredDefaultNotes
maxMinutesstringNo""
coursestringNo

Response 200

{
  suggestions: {
    score: number
    reasons: string[]
    recipe: {
      createdAt: number
      updatedAt: number
      title: string
      tags: string[]
      ownerId: string
      shared?: boolean
      favourite?: boolean
      recipeId: string
      servings: number
      totalMinutes?: number
      cuisines: string[]
      courses: string[]
      rating?: number
      household: boolean
      cookedCount: number
      lastCookedAt?: number
      diets: string[]
      allergens: string[]
      kcalPerServing?: number
      ingredientIds: string[]
      amounts?: {
        [key: string]: {
          g?: number
          ml?: number
          each?: number
          minor?: true
        }
      }
      measuredLines?: number
      image?: {
        imageId: string
        versionId?: string
        mime?: string
        width?: number
        height?: number
        alt?: string
        url: string
        thumbUrl: string
      }
    }
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

GET /v1/me/food/substitutes

Substitutes for an ingredient from Food's kitchen notes, with amounts (none on file: an empty list and a note).

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Query parameterTypeRequiredNotes
ingredientstringYes1–100 characters

Response 200

{
  note?: string
  ingredient: string
  substitutes: {
    use: string
    note?: string
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

GET /v1/me/food/widget

The phone's widgets: tonight's dinner and the first list's next items.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  today: string
  tonight: null | {
    title: string
    meal: string
    recipeId?: string
    minutes?: number
    imageUrl?: string
  }
  list: null | {
    listId: string
    name: string
    remaining: number
    items: {
      itemId: string
      name: string
      amount: string
      aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
    }[]
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

POST /v1/me/food/imports/url

A web page's recipe as a draft to check (schema.org data, else its lists); a page without either is read by the model as an import.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
urlstringYes4–2,000 characters

Response 200

{
  draft?: {
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags?: string[]
    steps?: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    publicToken?: string
    servings?: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients?: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines?: string[]
    courses?: string[]
    claimedDiets?: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons?: "au" | "us"
    notes?: string
    rating?: number
    household?: boolean
    lastCookedAt?: number
    imageUrls?: string[]
  }
  from?: string
  import?: {
    importId: string
    kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
    status: "done" | "failed" | "running"
    label: string
    recipeIds: string[]
    skipped: number
    error?: string
    createdAt: number
    updatedAt: number
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/imports/text

Recipes in pasted text as drafts to check (several when separated by a line of dashes).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
textstringYes1–100,000 characters

Response 200

{
  drafts: {
    title: string
    description?: string
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    tags?: string[]
    steps?: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    favourite?: boolean
    publicToken?: string
    servings?: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients?: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    cuisines?: string[]
    courses?: string[]
    claimedDiets?: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons?: "au" | "us"
    notes?: string
    rating?: number
    household?: boolean
    lastCookedAt?: number
    imageUrls?: string[]
    images?: string[]
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/imports/photos

Photos or screenshots of one recipe (base64, up to four), read by the model; poll the import for its draft.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body (up to 10 MB)

FieldTypeRequiredNotes
photosstring[]Yes1–4 items; each 10–12,000,000 characters

Response 202

{
  import: {
    importId: string
    kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
    status: "done" | "failed" | "running"
    label: string
    recipeIds: string[]
    skipped: number
    error?: string
    createdAt: number
    updatedAt: number
    draft?: {
      title: string
      description?: string
      source?: {
        kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
        url?: string
        name?: string
        author?: string
      }
      tags?: string[]
      steps?: {
        id: string
        section?: string
        text: string
        timers?: {
          seconds: number
          label?: string
        }[]
      }[]
      favourite?: boolean
      publicToken?: string
      servings?: number
      yieldLabel?: string
      prepMinutes?: number
      cookMinutes?: number
      totalMinutes?: number
      ingredients?: {
        id: string
        section?: string
        quantity?: number
        quantityMax?: number
        unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
        item: string
        note?: string
        ingredientId?: string
        optional?: boolean
      }[]
      cuisines?: string[]
      courses?: string[]
      claimedDiets?: string[]
      difficulty?: "easy" | "medium" | "hard"
      spoons?: "au" | "us"
      notes?: string
      rating?: number
      household?: boolean
      lastCookedAt?: number
      imageUrls?: string[]
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.
413That's too large. Send pictures of at most 8 MB, four at a time.

POST /v1/me/food/imports/files

Starts importing another app's export: a link to PUT the file to, then complete.

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Request body

FieldTypeRequiredNotes
namestringYes1–200 characters
sizeintegerYes≥ 1

Response 201

{
  importId: string
  uploadUrl: string
  contentType: string
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

POST /v1/me/food/imports/:importId/complete

The file has been sent: the worker reads it and saves its recipes (and Melt's cookbooks as collections).

Auth: user access token or platform agent key · Scope: food:write (when actor.type === "user")

Path parameterDescription
:importIdTakeout import id (imp_…); under me/food a Food import (fim_…).

Response 202

{
  import: {
    importId: string
    kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
    status: "done" | "failed" | "running"
    label: string
    recipeIds: string[]
    skipped: number
    error?: string
    createdAt: number
    updatedAt: number
    draft?: {
      title: string
      description?: string
      source?: {
        kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
        url?: string
        name?: string
        author?: string
      }
      tags?: string[]
      steps?: {
        id: string
        section?: string
        text: string
        timers?: {
          seconds: number
          label?: string
        }[]
      }[]
      favourite?: boolean
      publicToken?: string
      servings?: number
      yieldLabel?: string
      prepMinutes?: number
      cookMinutes?: number
      totalMinutes?: number
      ingredients?: {
        id: string
        section?: string
        quantity?: number
        quantityMax?: number
        unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
        item: string
        note?: string
        ingredientId?: string
        optional?: boolean
      }[]
      cuisines?: string[]
      courses?: string[]
      claimedDiets?: string[]
      difficulty?: "easy" | "medium" | "hard"
      spoons?: "au" | "us"
      notes?: string
      rating?: number
      household?: boolean
      lastCookedAt?: number
      imageUrls?: string[]
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:write on a key made by a person.

GET /v1/me/food/imports

Your imports from the last two weeks: what they read, saved and skipped, or why they failed.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  imports: {
    importId: string
    kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
    status: "done" | "failed" | "running"
    label: string
    recipeIds: string[]
    skipped: number
    error?: string
    createdAt: number
    updatedAt: number
    draft?: {
      title: string
      description?: string
      source?: {
        kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
        url?: string
        name?: string
        author?: string
      }
      tags?: string[]
      steps?: {
        id: string
        section?: string
        text: string
        timers?: object[]
      }[]
      favourite?: boolean
      publicToken?: string
      servings?: number
      yieldLabel?: string
      prepMinutes?: number
      cookMinutes?: number
      totalMinutes?: number
      ingredients?: {
        id: string
        section?: string
        quantity?: number
        quantityMax?: number
        unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
        item: string
        note?: string
        ingredientId?: string
        optional?: boolean
      }[]
      cuisines?: string[]
      courses?: string[]
      claimedDiets?: string[]
      difficulty?: "easy" | "medium" | "hard"
      spoons?: "au" | "us"
      notes?: string
      rating?: number
      household?: boolean
      lastCookedAt?: number
      imageUrls?: string[]
    }
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

GET /v1/me/food/imports/:importId

One import: its status and, for one recipe read from photos or a page, the draft to check.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Path parameterDescription
:importIdTakeout import id (imp_…); under me/food a Food import (fim_…).

Response 200

{
  import: {
    importId: string
    kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
    status: "done" | "failed" | "running"
    label: string
    recipeIds: string[]
    skipped: number
    error?: string
    createdAt: number
    updatedAt: number
    draft?: {
      title: string
      description?: string
      source?: {
        kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
        url?: string
        name?: string
        author?: string
      }
      tags?: string[]
      steps?: {
        id: string
        section?: string
        text: string
        timers?: {
          seconds: number
          label?: string
        }[]
      }[]
      favourite?: boolean
      publicToken?: string
      servings?: number
      yieldLabel?: string
      prepMinutes?: number
      cookMinutes?: number
      totalMinutes?: number
      ingredients?: {
        id: string
        section?: string
        quantity?: number
        quantityMax?: number
        unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
        item: string
        note?: string
        ingredientId?: string
        optional?: boolean
      }[]
      cuisines?: string[]
      courses?: string[]
      claimedDiets?: string[]
      difficulty?: "easy" | "medium" | "hard"
      spoons?: "au" | "us"
      notes?: string
      rating?: number
      household?: boolean
      lastCookedAt?: number
      imageUrls?: string[]
    }
  }
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.

GET /v1/me/food/export

Everything of yours in Food as a file Food imports again (format: cactive-food): recipes, collections, settings and history. Pictures are links valid for an hour.

Auth: user access token or platform agent key · Scope: food:read (when actor.type === "user")

Response 200

{
  format: string
  version: number
  exportedAt: string
  settings: {
    measure: "metric" | "original" | "imperial"
    spoons: "au" | "us"
    defaultServings: number
    diets: string[]
    avoidAllergens: string[]
    weeknightMinutes?: number
    weatherSuggestions: boolean
    healthLogging: boolean
    calendar?: {
      orgId: string
      calendarId: string
    }
    weekStartsOn: number
    receiptMail?: {
      orgId: string
      mailboxId: string
      address: string
      since: number
      backfilledAt?: number
    }
    useSoonAlerts: boolean
    voiceControl: boolean
    weeklyBudget?: number
    timeZone?: string
  }
  recipes: {
    imageUrls?: string[]
    recipeId: string
    ownerId: string
    title: string
    description?: string
    servings: number
    yieldLabel?: string
    prepMinutes?: number
    cookMinutes?: number
    totalMinutes?: number
    ingredients: {
      id: string
      section?: string
      quantity?: number
      quantityMax?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      item: string
      note?: string
      ingredientId?: string
      optional?: boolean
    }[]
    steps: {
      id: string
      section?: string
      text: string
      timers?: {
        seconds: number
        label?: string
      }[]
    }[]
    cuisines: string[]
    courses: string[]
    claimedDiets: string[]
    tags: string[]
    difficulty?: "easy" | "medium" | "hard"
    spoons: "au" | "us"
    source?: {
      kind: "text" | "photo" | "web" | "manual" | "melt" | "paprika" | "mela" | "crouton" | "copymethat" | "assistant" | "copy"
      url?: string
      name?: string
      author?: string
    }
    notes?: string
    rating?: number
    favourite?: boolean
    household: boolean
    cookedCount: number
    lastCookedAt?: number
    createdAt: number
    updatedAt: number
    version: number
  }[]
  collections: {
    name: string
    description?: string
    recipeIds: string[]
  }[]
  household: {
    name: string
    members: {
      name?: string
      role: "owner" | "member"
      joinedAt: string
    }[]
    plan: {
      [key: string]: unknown
    }[]
    lists: {
      listId: string
      homeId: string
      name: string
      items: {
        itemId: string
        name: string
        quantity?: number
        unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
        amount?: string
        aisle: "none" | "other" | "household" | "meat" | "dairy" | "breakfast" | "baking" | "produce" | "bakery" | "seafood" | "deli" | "chilled" | "pasta" | "canned" | "condiments" | "oils" | "spices" | "nuts" | "spreads" | "frozen" | "drinks"
        ingredientId?: string
        note?: string
        checked: boolean
        forRecipes?: string[]
        addedBy: string
        addedAt: number
        checkedBy?: string
      }[]
      createdAt: number
      updatedAt: number
      version: number
    }[]
    pantry: {
      itemId: string
      name: string
      ingredientId?: string
      quantity?: number
      unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
      place: "fridge" | "freezer" | "pantry"
      useBy?: string
      addedBy: string
      addedAt: number
      source?: "photo" | "manual" | "receipt" | "leftovers" | "barcode"
      barcode?: string
      leftover?: {
        recipeId: string
        title: string
        portions: number
        cookedOn: string
      }
    }[]
    receipts: {
      receiptId: string
      store: string
      storeName: string
      purchasedOn: string
      total?: number
      lines: {
        id: string
        text: string
        name: string
        ingredientId?: string
        quantity?: number
        unit?: "slice" | "g" | "kg" | "mg" | "oz" | "lb" | "ml" | "l" | "tsp" | "tbsp" | "cup" | "floz" | "pint" | "quart" | "pinch" | "dash" | "piece" | "clove" | "can" | "jar" | "bunch" | "handful" | "sprig" | "sheet" | "packet" | "stick" | "head" | "fillet" | "rasher" | "leaf" | "stalk"
        price?: number
        detail?: string
        food: boolean
        place?: "fridge" | "freezer" | "pantry"
        useBy?: string
      }[]
      status: "added" | "dismissed" | "new"
      via: "upload" | "mail" | "forward"
      read: "model" | "rules"
      userId?: string
      createdAt: number
      addedAt?: number
      addedBy?: string
      added?: number
    }[]
    prices: {
      key: string
      ingredientId?: string
      name: string
      paid: number
      perG?: number
      perMl?: number
      perEach?: number
      store: string
      storeName: string
      day: string
    }[]
  }
  cooked: {
    note?: string
    rating?: number
    recipeId: string
    title: string
    at: string
  }[]
}

Errors

StatusMessage
403Food isn't available to the phone assistant.
403Food is reachable from the Food and phone apps.
403Food needs food:read on a key made by a person.