{
  "openapi": "3.1.0",
  "info": {
    "title": "FitVete Food & Nutrition API",
    "version": "1.7.0",
    "description": "Query a curated, confidence-scored database of foods, recipes, drinks, and full micronutrient breakdowns over a simple REST API \u2014 plus barcode lookup and AI vision for meal photos and Nutrition Facts labels.\n\nAuthentication is accepted only in the `x-api-key` request header. Requests are metered by daily points: most endpoints cost 1 point, image (vision) endpoints cost 10. Every response includes quota headers. X-RateLimit-Cost reports the cost reserved. Authorization reserves points before handler processing; handler errors and cache hits retain that cost. Rejected auth, quota/burst gates and invalid image uploads cost zero. Unknown account usage has zero headers and X-Plan unknown. Daily budgets reset at UTC midnight. Results carry a `source` field: `corpus` = served from our curated dataset, `corpus-parser` = computed by FitVete's own ingredient parser against the owned dataset, and `reference-provider`/`usda`/`apileague`/`openfoodfacts`/`vision` = freshly fetched and evaluated for eligible reference promotion (private scans and descriptions are never shared; external providers are fallbacks). Public response URLs always use FitVete domains: approved images are cached in FitVete Storage and external source links are not exposed. Attribution text and license metadata remain available. Open Food Facts\u2013derived data is ODbL-licensed. A `503` means authorization or required storage is temporarily unavailable; retry with backoff.\n",
    "contact": {
      "name": "FitVete API support",
      "email": "api@fitvete.com",
      "url": "https://fitvete.com/api/"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://fitvete.com/api/"
    }
  },
  "servers": [
    {
      "url": "https://auth.fitvete.com/functions/v1/food-api",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    }
  ],
  "tags": [
    {
      "name": "Foods"
    },
    {
      "name": "Recipes"
    },
    {
      "name": "Drinks"
    },
    {
      "name": "Barcode"
    },
    {
      "name": "Vision"
    },
    {
      "name": "Intelligence"
    }
  ],
  "paths": {
    "/v1/search-foods": {
      "get": {
        "tags": [
          "Foods"
        ],
        "summary": "Search foods by name",
        "description": "Hybrid lexical and semantic discovery. Semantic indexing covers generic reference foods; branded products retain lexical/barcode lookup. Match scores are not nutrition accuracy. Cost: 1 point.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "chicken",
            "description": "Food name."
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            },
            "description": "Max results."
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hybrid",
                "semantic",
                "lexical"
              ],
              "default": "hybrid"
            },
            "description": "Semantic-only mode returns 503 if its encoder is unavailable; hybrid retains lexical fallback."
          }
        ],
        "responses": {
          "200": {
            "description": "Matching foods.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "corpus",
                        "usda"
                      ]
                    },
                    "retrieval": {
                      "type": "object",
                      "properties": {
                        "requested": {
                          "type": "string"
                        },
                        "semantic_available": {
                          "type": "boolean"
                        },
                        "model": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    "foods": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Food"
                      }
                    }
                  }
                },
                "example": {
                  "number": 1,
                  "source": "corpus",
                  "foods": [
                    {
                      "name": "chicken breast",
                      "calories": 120,
                      "protein_g": 22,
                      "carbs_g": 0,
                      "fat_g": 3,
                      "confidence": 100,
                      "source": "corpus"
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "Semantic encoder or index unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "429": {
            "$ref": "#/components/responses/BurstLimited"
          }
        }
      }
    },
    "/v1/compute-nutrition": {
      "get": {
        "tags": [
          "Foods"
        ],
        "summary": "Compute nutrition for an ingredient list",
        "description": "Nutrition with macros, available measured micronutrients, properties and caloric breakdown for a free-text ingredient list. Computed by FitVete's own parser against the owned corpus first (`source: corpus-parser`), then licensed reference provider, then API League; `source` reflects the provider. Cost: 1 point.",
        "parameters": [
          {
            "name": "ingredients",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "1 cup rice",
            "description": "One or more ingredients; separate lines with newlines."
          }
        ],
        "responses": {
          "200": {
            "description": "Computed nutrition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComputedNutrition"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/recipes/search": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "Search recipes by name and filters",
        "description": "Name search plus rich filters. A bare name query is served corpus-first; filtered/paged searches run upstream. Returns id, title, image, ready time, and calories per result. Cost: 1 point.\n",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "pasta",
            "description": "Name or keywords (optional if filters are given)."
          },
          {
            "name": "diet",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "vegetarian",
            "description": "e.g. vegetarian, vegan, ketogenic, paleo."
          },
          {
            "name": "cuisine",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "italian",
            "description": "See GET /v1/recipes/cuisines."
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "main course",
            "description": "Meal type; see GET /v1/recipes/meal-types. Alias: mealType."
          },
          {
            "name": "intolerances",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "gluten",
            "dairy": null,
            "description": "Comma-separated."
          },
          {
            "name": "includeIngredients",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "tomato",
            "basil": null,
            "description": "Comma-separated must-include."
          },
          {
            "name": "excludeIngredients",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "peanut",
            "description": "Comma-separated must-exclude."
          },
          {
            "name": "maxReadyTime",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "example": 30,
            "description": "Max minutes to prepare."
          },
          {
            "name": "minCalories",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "maxCalories",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          {
            "name": "minProtein",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "example": 20
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "popularity",
            "description": "e.g. popularity, calories, time, protein."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 900
            },
            "description": "Pagination offset."
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching recipes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "totalResults": {
                      "type": "integer"
                    },
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "recipes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "image": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "ready_in_minutes": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "calories": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          }
        }
      }
    },
    "/v1/recipes/random": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "Get random recipes",
        "description": "Random full recipes, harvested into the corpus. Cost: 1 point.",
        "parameters": [
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 5
            }
          },
          {
            "name": "tags",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "vegetarian",
            "dessert": null,
            "description": "Comma-separated diet/meal tags."
          }
        ],
        "responses": {
          "200": {
            "description": "Random recipes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "recipes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/recipes/autocomplete": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "Autocomplete recipe titles",
        "description": "Title suggestions for a partial query. Cost: 1 point.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "choc"
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suggestions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "suggestions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "title": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/recipes/by-nutrients": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "Find recipes by nutrient ranges",
        "description": "Match recipes to calorie/protein/carb/fat ranges. At least one range required. Cost: 1 point.",
        "parameters": [
          {
            "name": "minCalories",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "maxCalories",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "example": 600
          },
          {
            "name": "minProtein",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "example": 30
          },
          {
            "name": "maxProtein",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "minCarbs",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "maxCarbs",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "minFat",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "maxFat",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching recipes with per-recipe macros.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "recipes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "image": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "calories": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "protein_g": {
                            "type": "integer"
                          },
                          "carbs_g": {
                            "type": "integer"
                          },
                          "fat_g": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/recipes/diets": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "List supported diet filters",
        "description": "Reference list (no upstream call). Cost: 1 point.",
        "responses": {
          "200": {
            "description": "Supported diets.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "diets": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/recipes/meal-types": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "List supported meal types",
        "description": "Reference list (no upstream call). Cost: 1 point.",
        "responses": {
          "200": {
            "description": "Supported meal types.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "meal_types": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/recipes/cuisines": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "List supported cuisines",
        "description": "Reference list (no upstream call). Cost: 1 point.",
        "responses": {
          "200": {
            "description": "Supported cuisines.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "cuisines": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/recipes/{id}/similar": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "Find similar recipes",
        "description": "Recipes similar to the given id. Cost: 1 point.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 715538
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 5
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Similar recipes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "recipes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "ready_in_minutes": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "servings": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "source_url": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Reserved for a FitVete canonical URL; external source URLs are never returned."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/recipes/{id}": {
      "get": {
        "tags": [
          "Recipes"
        ],
        "summary": "Get full recipe detail",
        "description": "Images, dietary properties, nutrition, ingredients with measures, and step-by-step instructions. Optional servings scaler. Cost: 1 point.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 715538
          },
          {
            "name": "servings",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Add a serving_scale block with macros scaled to this many servings."
          }
        ],
        "responses": {
          "200": {
            "description": "Full recipe payload (provider-shaped) plus a `source` field (and `serving_scale` if servings given).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/drinks/search": {
      "get": {
        "tags": [
          "Drinks"
        ],
        "summary": "Search drinks and cocktails",
        "description": "Flavors, glass type, ingredients, and nutrition. Cost: 1 point.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "margarita"
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching drinks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "drinks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/barcode/{code}": {
      "get": {
        "tags": [
          "Barcode"
        ],
        "summary": "Look up a packaged food by barcode",
        "description": "UPC/EAN lookup (Open Food Facts), harvested into the corpus. Cost: 1 point.",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "3017620422003",
            "description": "Numeric UPC/EAN."
          }
        ],
        "responses": {
          "200": {
            "description": "Product found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BarcodeProduct"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/score": {
      "post": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Personalized health score for a food",
        "description": "Deterministic 0\u2013100 score + A\u2013F grade for a food, personalized to the user's profile. Rubric: Nutri-Score-derived base (penalize energy, saturated fat, sugar, sodium; reward fiber, protein), minus an ultra-processing (NOVA) penalty, then profile modifiers. An allergen or avoid-list match forces grade F. Cost: 3 points.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "food": {
                    "type": "object",
                    "description": "Reference the food by one of name, barcode, or id.",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "barcode": {
                        "type": "string"
                      },
                      "id": {
                        "type": "string"
                      }
                    }
                  },
                  "profile": {
                    "type": "object",
                    "properties": {
                      "goals": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "example": [
                          "build muscle",
                          "low sugar"
                        ]
                      },
                      "diet": {
                        "type": "string",
                        "example": "vegan"
                      },
                      "allergies": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "example": [
                          "milk",
                          "peanut"
                        ]
                      },
                      "avoid": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "example": [
                          "palm oil"
                        ]
                      }
                    }
                  },
                  "explain": {
                    "type": "boolean",
                    "description": "Add a one-line natural-language summary."
                  }
                },
                "required": [
                  "food"
                ]
              },
              "example": {
                "food": {
                  "name": "chicken breast"
                },
                "profile": {
                  "goals": [
                    "build muscle"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Score result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "food": {
                      "type": "string"
                    },
                    "score": {
                      "type": "integer",
                      "description": "0\u2013100."
                    },
                    "grade": {
                      "type": "string",
                      "description": "A\u2013E",
                      "or F for allergen/avoid hits.": null
                    },
                    "reasons": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "flags": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string"
                          },
                          "value": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "eco_score": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "nova": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "summary": {
                      "type": "string",
                      "description": "Present only when `explain` is true."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/analyze-ingredients": {
      "post": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Analyze an ingredient list",
        "description": "Detect additives/E-numbers, allergens, NOVA ultra-processing level, and vegan/vegetarian/gluten-free flags. Cost: 2 points.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ingredients": {
                    "type": "string"
                  }
                },
                "required": [
                  "ingredients"
                ]
              },
              "example": {
                "ingredients": "sugar, palm oil, hazelnuts, skim milk, cocoa, soy lecithin, E471"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ingredient analysis.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "additives": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "concern": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "allergens": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "nova": {
                      "type": "integer",
                      "description": "1\u20134 ultra-processing level."
                    },
                    "nova_reason": {
                      "type": "string"
                    },
                    "vegan": {
                      "type": "boolean"
                    },
                    "vegetarian": {
                      "type": "boolean"
                    },
                    "gluten_free": {
                      "type": "boolean"
                    },
                    "reasons": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/parse": {
      "post": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Parse a free-text meal (NLP)",
        "description": "Identify foods and quantities, then resolve nutrition from reference records. Unresolved items have resolved=false and null nutrition; incomplete meals have null totals plus resolved_totals for the resolved subtotal. The language model never supplies calories. Cost: 5 points.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string"
                  }
                },
                "required": [
                  "text"
                ]
              },
              "example": {
                "text": "2 eggs and a slice of whole wheat toast with butter"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed meal.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "complete": {
                      "type": "boolean"
                    },
                    "unresolved_items": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "resolved_totals": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "text": {
                      "type": "string"
                    },
                    "calories": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "protein_g": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "carbs_g": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "fat_g": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "quantity": {
                            "type": "number"
                          },
                          "unit": {
                            "type": "string"
                          },
                          "calories": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "protein_g": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "carbs_g": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "fat_g": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/Unreadable"
          },
          "502": {
            "$ref": "#/components/responses/ProviderDown"
          }
        }
      }
    },
    "/v1/alternatives": {
      "get": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Healthier alternatives",
        "description": "Higher-scoring swaps for a food from the catalog, ranked. Cost: 1 point.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "dark chocolate"
          },
          {
            "name": "barcode",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 5
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked alternatives.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "for": {
                      "type": "string"
                    },
                    "base_score": {
                      "type": "integer"
                    },
                    "base_grade": {
                      "type": "string"
                    },
                    "alternatives": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "calories": {
                            "type": "integer"
                          },
                          "protein_g": {
                            "type": "integer"
                          },
                          "carbs_g": {
                            "type": "integer"
                          },
                          "fat_g": {
                            "type": "integer"
                          },
                          "score": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/foods/autocomplete": {
      "get": {
        "tags": [
          "Foods"
        ],
        "summary": "Food name typeahead",
        "description": "Fast food name suggestions from the corpus (upstream fallback). Cost: 1 point.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "chick"
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suggestions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "number": {
                      "type": "integer"
                    },
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "suggestions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "calories": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/nutrition-from-photo": {
      "post": {
        "tags": [
          "Vision"
        ],
        "summary": "Estimate meal nutrition from a photo",
        "description": "Vision identifies foods and estimates grams; reference data supplies macros and nutrients. Unresolved food returns 422. Cost: 10 points. Send multipart field `image`, or POST raw bytes with an image/* content-type. Max 5 MB; JPEG/PNG/WebP.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary"
                  }
                },
                "required": [
                  "image"
                ]
              }
            },
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/png": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/webp": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estimated meal nutrition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhotoNutrition"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMedia"
          },
          "422": {
            "$ref": "#/components/responses/Unreadable"
          },
          "502": {
            "$ref": "#/components/responses/ProviderDown"
          }
        }
      }
    },
    "/v1/nutrition-label": {
      "post": {
        "tags": [
          "Vision"
        ],
        "summary": "Parse a Nutrition Facts label from a photo",
        "description": "AI vision transcribes a Nutrition Facts label into structured fields. Cost: 10 points. Send multipart field `image`, or POST raw bytes with an image/* content-type. Max 5 MB; JPEG/PNG/WebP.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary"
                  }
                },
                "required": [
                  "image"
                ]
              }
            },
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/png": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/webp": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed label.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LabelNutrition"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMedia"
          },
          "422": {
            "$ref": "#/components/responses/Unreadable"
          },
          "502": {
            "$ref": "#/components/responses/ProviderDown"
          }
        }
      }
    },
    "/v1/scans/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Vision"
        ],
        "summary": "Retrieve a private saved scan",
        "description": "Direct developer keys only; isolated to your developer account. Active for 30 days from creation. Returns the latest correction when available. Cost: 0 points; per-minute limits still apply. Authorize your own end user before exposing a scan.",
        "responses": {
          "200": {
            "description": "Latest saved result and revision.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Direct developer key required."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/BurstLimited"
          },
          "503": {
            "description": "Scan storage temporarily unavailable."
          }
        }
      },
      "delete": {
        "tags": [
          "Vision"
        ],
        "summary": "Delete private scan memory and its learning eligibility",
        "description": "Deletion scoped to the direct developer account; missing, expired or other-account scans return 404. Cost: 0 points. Does not delete separately saved meal logs.",
        "responses": {
          "200": {
            "description": "Scan absent from your account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Direct developer key required."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/BurstLimited"
          },
          "503": {
            "description": "Scan storage temporarily unavailable."
          }
        }
      }
    },
    "/v1/scans/{id}/feedback": {
      "post": {
        "tags": [
          "Vision"
        ],
        "summary": "Correct a scan for private reuse",
        "description": "Direct developer keys only. Cost: 0 points. Send complete corrected meal totals, not a patch. Corrections replace previous micronutrients with an empty array to avoid keeping inconsistent estimates. They are user-provided and not independently verified. Shared evaluation contribution is off by default and requires explicit end-user permission, consent_version scan-facts-v1, and later human review. Never set consent automatically. See /api/scan-learning.md.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScanFeedback"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Corrected result with incremented scan_revision.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Direct developer key required."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Revision conflict. Fetch the latest result before deciding whether to retry."
          },
          "413": {
            "description": "Feedback exceeds 20000 characters."
          },
          "429": {
            "$ref": "#/components/responses/BurstLimited"
          },
          "503": {
            "description": "Scan storage temporarily unavailable."
          }
        }
      }
    },
    "/v1/identify": {
      "post": {
        "tags": [
          "Foods"
        ],
        "summary": "Identify a barcode, description, label or photo",
        "description": "Direct keys only. Dispatches once to barcode (1 point), parse (5 points), or photo/label (10 points). Same validation, error and output contracts as the selected endpoint. Models supply identity and portions; reference data supplies text/photo nutrition. Images are limited to 5 MB after decoding.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "barcode",
                      "text",
                      "photo",
                      "label"
                    ]
                  },
                  "barcode": {
                    "type": "string"
                  },
                  "text": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "image_base64": {
                    "type": "string",
                    "description": "Required for photo or label; base64 image bytes."
                  },
                  "content_type": {
                    "type": "string",
                    "enum": [
                      "image/jpeg",
                      "image/png",
                      "image/webp"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The selected identification endpoint response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMedia"
          },
          "422": {
            "$ref": "#/components/responses/Unreadable"
          },
          "502": {
            "$ref": "#/components/responses/ProviderDown"
          }
        }
      }
    },
    "/v1/foods/search": {
      "get": {
        "tags": [
          "Foods"
        ],
        "summary": "Search foods (resource alias)",
        "description": "Alias of /v1/search-foods. Same result and single 1-point cost.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "number",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 25,
              "default": 10
            }
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hybrid",
                "semantic",
                "lexical"
              ],
              "default": "hybrid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Food search result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "$ref": "#/components/schemas/Source"
                    },
                    "foods": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Food"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/foods/{id}": {
      "get": {
        "tags": [
          "Foods"
        ],
        "summary": "Retrieve a reference or account-owned food",
        "description": "Cost 1 point. Other-account private food IDs return 404.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Food nutrition on the explicit 100g basis.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Food"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/foods": {
      "post": {
        "tags": [
          "Foods"
        ],
        "summary": "Create a private food",
        "description": "Cost 1 point. Direct key required. Private user-supplied facts are unverified and never join reference data or training. Enforce your own end-user permissions. Creation is not idempotent; do not blindly retry an uncertain response. Account deletion removes private foods and logs.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "nutrition_basis",
                  "calories",
                  "protein_g",
                  "carbs_g",
                  "fat_g"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "nutrition_basis": {
                    "type": "string",
                    "enum": [
                      "100g"
                    ]
                  },
                  "calories": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1000
                  },
                  "protein_g": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "carbs_g": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  },
                  "fat_g": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created private food and UUID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Food"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Missing or implausible nutrition.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/logs": {
      "post": {
        "tags": [
          "Foods"
        ],
        "summary": "Log a portion using server-calculated nutrition",
        "description": "Cost 1 point. Direct key required. Only reference foods and your account's private foods can be logged. Private account data is excluded from shared reference data and training. Creation is not idempotent.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "food_id",
                  "grams"
                ],
                "properties": {
                  "food_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "grams": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 3000
                  },
                  "logged_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Saved private log.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "food_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "grams": {
                      "type": "number"
                    },
                    "nutrition": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "number"
                      }
                    },
                    "logged_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your API key (fv_live_\u2026). Get one free at https://fitvete.com/api/"
      }
    },
    "schemas": {
      "Source": {
        "type": "string",
        "enum": [
          "corpus",
          "corpus-parser",
          "usda",
          "apileague",
          "openfoodfacts",
          "vision",
          "vision+corpus",
          "scan-memory",
          "user-correction",
          "reference-provider"
        ]
      },
      "ScanResult": {
        "type": "object",
        "additionalProperties": true,
        "description": "Latest photo/label prediction or complete corrected meal totals, with private memory metadata.",
        "properties": {
          "scan_saved": {
            "type": "boolean"
          },
          "scan_id": {
            "type": "string",
            "format": "uuid"
          },
          "scan_revision": {
            "type": "integer",
            "minimum": 0
          },
          "scan_expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "contribution_status": {
            "type": "string",
            "enum": [
              "private",
              "awaiting_review"
            ]
          }
        }
      },
      "ScanFeedback": {
        "type": "object",
        "required": [
          "scan_revision",
          "correction"
        ],
        "properties": {
          "scan_revision": {
            "type": "integer",
            "minimum": 0
          },
          "contribute_to_training": {
            "type": "boolean",
            "default": false
          },
          "consent_version": {
            "type": "string",
            "enum": [
              "scan-facts-v1"
            ]
          },
          "correction": {
            "type": "object",
            "required": [
              "name",
              "calories",
              "protein_g",
              "carbs_g",
              "fat_g"
            ],
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 160,
                "description": "Food name only; no personal information or links."
              },
              "calories": {
                "type": "number",
                "minimum": 0,
                "maximum": 10000
              },
              "protein_g": {
                "type": "number",
                "minimum": 0,
                "maximum": 1000
              },
              "carbs_g": {
                "type": "number",
                "minimum": 0,
                "maximum": 2000
              },
              "fat_g": {
                "type": "number",
                "minimum": 0,
                "maximum": 1000
              },
              "water_ml": {
                "type": "number",
                "minimum": 0,
                "maximum": 10000
              }
            }
          }
        }
      },
      "Nutrient": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "example": "fiber"
          },
          "name": {
            "type": "string",
            "example": "Fiber"
          },
          "amount": {
            "type": "number",
            "example": 0.6
          },
          "unit": {
            "type": "string",
            "example": "g"
          },
          "percent_of_daily_needs": {
            "type": "number",
            "example": 2.4
          }
        }
      },
      "Food": {
        "type": "object",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "food_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "brand": {
            "type": [
              "string",
              "null"
            ]
          },
          "barcode": {
            "type": [
              "string",
              "null"
            ]
          },
          "nutrition_basis": {
            "type": "string",
            "enum": [
              "100g"
            ]
          },
          "serving_size": {
            "type": [
              "string",
              "null"
            ]
          },
          "per_100g": {
            "type": "object",
            "additionalProperties": true
          },
          "match_kind": {
            "type": "string",
            "enum": [
              "alias",
              "exact",
              "token",
              "semantic"
            ]
          },
          "match_score": {
            "type": "number",
            "description": "Retrieval ranking signal; not an accuracy probability."
          },
          "nutrient_coverage": {
            "type": "object",
            "properties": {
              "reported_count": {
                "type": "integer",
                "description": "Number of distinct source-reported nutrient keys",
                "including nutrients beyond the core target.": null
              },
              "core_reported_count": {
                "type": "integer",
                "description": "Number of reported nutrients within the 26-key core target."
              },
              "target_count": {
                "type": "integer"
              },
              "reported_keys": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "unknown_keys": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "complete": {
                "type": "boolean"
              },
              "basis": {
                "type": "string",
                "enum": [
                  "source_reported"
                ]
              },
              "imputed": {
                "type": "boolean",
                "const": false
              }
            }
          },
          "nutrients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Nutrient"
            }
          },
          "eco_score": {
            "type": [
              "string",
              "null"
            ]
          },
          "nova": {
            "type": [
              "integer",
              "null"
            ]
          },
          "license": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_attribution": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "calories": {
            "type": "number",
            "description": "Per 100 g."
          },
          "protein_g": {
            "type": "number"
          },
          "carbs_g": {
            "type": "number"
          },
          "fat_g": {
            "type": "number"
          },
          "confidence": {
            "type": "number",
            "description": "0\u2013100; provenance/consistency signal",
            "not a measured accuracy percentage.": null
          },
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "attributes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Derived badges such as high-protein or low-sugar."
          }
        }
      },
      "ComputedNutrition": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "calories": {
            "type": "integer"
          },
          "protein_g": {
            "type": "integer"
          },
          "carbs_g": {
            "type": "integer"
          },
          "fat_g": {
            "type": "integer"
          },
          "nutrients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Nutrient"
            }
          },
          "confidence": {
            "type": "number"
          }
        }
      },
      "BarcodeProduct": {
        "type": "object",
        "properties": {
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "found": {
            "type": "boolean"
          },
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "brand": {
            "type": [
              "string",
              "null"
            ]
          },
          "calories": {
            "type": "integer"
          },
          "protein_g": {
            "type": "integer"
          },
          "carbs_g": {
            "type": "integer"
          },
          "fat_g": {
            "type": "integer"
          },
          "serving": {
            "type": [
              "string",
              "null"
            ]
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "FitVete-hosted public image URL, or null when the image could not be safely cached."
          },
          "attributes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Derived badges such as high-protein or low-sugar."
          },
          "eco_score": {
            "type": [
              "string",
              "null"
            ],
            "description": "Open Food Facts Eco-Score grade (a\u2013e) when known."
          },
          "nova": {
            "type": [
              "integer",
              "null"
            ],
            "description": "NOVA processing level 1\u20134 (from the product",
            "else inferred from ingredients).": null
          }
        }
      },
      "PhotoNutrition": {
        "type": "object",
        "properties": {
          "scan_saved": {
            "type": "boolean",
            "description": "Always true on a successful direct developer scan. Raw images are not retained here; storage failure returns 503."
          },
          "scan_id": {
            "type": "string",
            "format": "uuid"
          },
          "scan_revision": {
            "type": "integer",
            "minimum": 0
          },
          "scan_expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "quality": {
            "type": "object",
            "additionalProperties": true,
            "description": "Portion and reference quality signals; not a guarantee of accuracy."
          },
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "name": {
            "type": "string"
          },
          "calories": {
            "type": "number"
          },
          "protein_g": {
            "type": "number"
          },
          "carbs_g": {
            "type": "number"
          },
          "fat_g": {
            "type": "number"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "calories": {
                  "type": "number"
                }
              }
            }
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "nutrients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Nutrient"
            }
          }
        }
      },
      "LabelNutrition": {
        "type": "object",
        "properties": {
          "scan_saved": {
            "type": "boolean",
            "description": "Always true on a successful direct developer scan. Raw images are not retained here; storage failure returns 503."
          },
          "scan_id": {
            "type": "string",
            "format": "uuid"
          },
          "scan_revision": {
            "type": "integer",
            "minimum": 0
          },
          "scan_expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "quality": {
            "type": "object",
            "additionalProperties": true,
            "description": "Portion and reference quality signals; not a guarantee of accuracy."
          },
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "calories": {
            "type": "number"
          },
          "protein_g": {
            "type": "number"
          },
          "carbs_g": {
            "type": "number"
          },
          "fat_g": {
            "type": "number"
          },
          "serving_size": {
            "type": [
              "string",
              "null"
            ]
          },
          "servings_per_container": {
            "type": [
              "number",
              "null"
            ]
          },
          "nutrients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Nutrient"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status",
          "code",
          "message"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "failure"
            ]
          },
          "code": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Missing or invalid parameter.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, invalid, or deleted API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QuotaExceeded": {
        "description": "Daily point limit reached \u2014 upgrade your plan.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BurstLimited": {
        "description": "Per-minute burst limit hit \u2014 retry after the Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds to wait."
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooLarge": {
        "description": "Image exceeds the 5 MB limit.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UnsupportedMedia": {
        "description": "Unsupported image type \u2014 use JPEG, PNG, or WebP.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unreadable": {
        "description": "Image is valid, but nutrition could not be read clearly.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ProviderDown": {
        "description": "Vision provider temporarily unavailable \u2014 retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
