{
  "openapi": "3.0.3",
  "info": {
    "title": "DietlyAPI",
    "version": "1.0.0",
    "description": "DietlyAPI is a fast food & nutrition API serving 4.2M+ foods with calories, macros, micronutrients, barcode lookup and confidence-ranked full-text search. Typical search responses return in ~40ms from EU-hosted infrastructure, with a public status page at https://www.getdietly.com/uptime.\n\nData is built primarily on Open Food Facts (ODbL) — normalized, deduped and plausibility-checked — plus Dietly community entries and clearly labeled AI estimates. If your app shows the data publicly, a one-line Open Food Facts credit is required.\n\nAuthentication is optional for the read endpoints below: anonymous requests share a per-IP limit of 30 requests/minute (with a small fairness delay). A free API key is issued instantly at https://www.getdietly.com/account — no card required. Paid plans get per-account limits and priority speed with no fairness delay.",
    "termsOfService": "https://www.getdietly.com/api-terms",
    "contact": {
      "name": "DietlyAPI support",
      "url": "https://www.getdietly.com/support?topic=api",
      "email": "dietly.main@gmail.com"
    },
    "license": {
      "name": "ODbL 1.0 (underlying Open Food Facts data)",
      "url": "https://opendatacommons.org/licenses/odbl/1-0/"
    },
    "x-apisguru-categories": ["food", "open_data"],
    "x-logo": {
      "url": "https://www.getdietly.com/logo.png"
    }
  },
  "externalDocs": {
    "description": "API guide and examples",
    "url": "https://www.getdietly.com/api-guide"
  },
  "servers": [
    { "url": "https://api.getdietly.com", "description": "Production (EU)" }
  ],
  "security": [{}, { "bearerAuth": [] }],
  "tags": [
    { "name": "Foods", "description": "Read-only nutrition data. Fast (~40ms typical) and public: works without a key at 30 req/min per IP; send a Bearer key for per-account limits and priority speed." },
    { "name": "Meta", "description": "Service health." }
  ],
  "paths": {
    "/search": {
      "get": {
        "tags": ["Foods"],
        "summary": "Search foods",
        "description": "Full-text + fuzzy trigram search across 4.2M+ foods, ranked by a confidence score (image-first re-ranking, typo rescue). Typical response time ~40ms.",
        "operationId": "searchFoods",
        "parameters": [
          { "name": "q", "in": "query", "required": true, "description": "Search term (min 2 characters)", "schema": { "type": "string", "minLength": 2 }, "example": "greek yogurt" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 } },
          { "name": "source", "in": "query", "description": "Filter by data source", "schema": { "type": "string", "enum": ["off", "claude"] } }
        ],
        "responses": {
          "200": {
            "description": "Ranked list of matching foods",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/FoodResult" } } } }
          },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/food/{food_id}": {
      "get": {
        "tags": ["Foods"],
        "summary": "Get a food by ID",
        "operationId": "getFood",
        "parameters": [
          { "name": "food_id", "in": "path", "required": true, "schema": { "type": "integer" }, "example": 764444 }
        ],
        "responses": {
          "200": { "description": "The food record", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FoodResult" } } } },
          "404": { "description": "Food not found" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/barcode/{code}": {
      "get": {
        "tags": ["Foods"],
        "summary": "Look up a food by barcode",
        "description": "Look up a food by EAN-13 or UPC-A barcode.",
        "operationId": "barcodeLookup",
        "parameters": [
          { "name": "code", "in": "path", "required": true, "schema": { "type": "string" }, "example": "0643126971962" }
        ],
        "responses": {
          "200": { "description": "The matching food", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FoodResult" } } } },
          "404": { "description": "No food with this barcode" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/foods/popular": {
      "get": {
        "tags": ["Foods"],
        "summary": "List popular foods",
        "description": "Paginated list of popular foods, optionally filtered by category.",
        "operationId": "popularFoods",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 100 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
          { "name": "category", "in": "query", "description": "Filter by category, e.g. 'Fruits'", "schema": { "type": "string" } },
          { "name": "has_image", "in": "query", "description": "Only return foods with a product image", "schema": { "type": "boolean", "default": true } }
        ],
        "responses": {
          "200": { "description": "List of foods", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/FoodResult" } } } } },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/foods/categories": {
      "get": {
        "tags": ["Foods"],
        "summary": "List food categories",
        "description": "All available food categories with item counts.",
        "operationId": "listCategories",
        "responses": {
          "200": {
            "description": "Categories with counts",
            "content": { "application/json": { "schema": { "type": "array", "items": { "type": "object", "properties": { "category": { "type": "string" }, "count": { "type": "integer" } } } }, "example": [{ "category": "Snacks", "count": 165922 }] } }
          },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/health": {
      "get": {
        "tags": ["Meta"],
        "summary": "Service health",
        "operationId": "health",
        "responses": {
          "200": {
            "description": "Service status and database size",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string" }, "foods_in_db": { "type": "integer" } } }, "example": { "status": "ok", "foods_in_db": 4247506 } } }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Optional for the endpoints in this spec. Get a free key instantly at https://www.getdietly.com/account (no card required)."
      }
    },
    "responses": {
      "RateLimited": {
        "description": "Rate limit exceeded. Check the Retry-After and X-RateLimit-* headers.",
        "headers": {
          "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" },
          "X-RateLimit-Limit": { "schema": { "type": "integer" } },
          "X-RateLimit-Remaining": { "schema": { "type": "integer" } },
          "X-RateLimit-Reset": { "schema": { "type": "integer" } }
        }
      }
    },
    "schemas": {
      "FoodResult": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": "string" },
          "brand": { "type": "string", "nullable": true },
          "barcode": { "type": "string", "nullable": true },
          "category": { "type": "string", "nullable": true },
          "serving_size_g": { "type": "number", "nullable": true },
          "serving_desc": { "type": "string", "nullable": true },
          "calories_kcal": { "type": "number", "nullable": true },
          "protein_g": { "type": "number", "nullable": true },
          "fat_g": { "type": "number", "nullable": true },
          "carbs_g": { "type": "number", "nullable": true },
          "fiber_g": { "type": "number", "nullable": true },
          "sugar_g": { "type": "number", "nullable": true },
          "sodium_mg": { "type": "number", "nullable": true },
          "saturated_fat_g": { "type": "number", "nullable": true },
          "cholesterol_mg": { "type": "number", "nullable": true },
          "potassium_mg": { "type": "number", "nullable": true },
          "image_url": { "type": "string", "nullable": true },
          "image_thumb_url": { "type": "string", "nullable": true },
          "source": { "type": "string", "description": "Data source: off (Open Food Facts), claude (labeled AI estimate) or community" },
          "confidence": { "type": "number", "description": "Data confidence score, 0–1" },
          "static_url": { "type": "string", "nullable": true, "description": "Path of the human-readable page on www.getdietly.com" }
        },
        "example": {
          "id": 764444,
          "name": "Banana",
          "brand": "Dole",
          "barcode": "0643126971962",
          "category": "Plant-based foods and beverages",
          "serving_size_g": 118.0,
          "serving_desc": "118g",
          "calories_kcal": 89.0,
          "protein_g": 1.1,
          "fat_g": 0.3,
          "carbs_g": 23.0,
          "fiber_g": 2.6,
          "sugar_g": 12.2,
          "sodium_mg": 0.0,
          "source": "off",
          "confidence": 0.9,
          "static_url": "food/44/banana-dole.html"
        }
      }
    }
  }
}
