{
  "openapi": "3.1.0",
  "info": {
    "title": "ZITBAR CAFE public data API",
    "version": "1.0.0",
    "summary": "Read-only facts about one neighbourhood cafe in Tel Aviv.",
    "description": "Read-only facts about one cafe: ZITBAR CAFE, Tagore 38, Neve Avivim, Ramat Aviv, Tel Aviv-Yafo, Israel.\n\nNo key, no auth, no rate limit. CORS is open to every origin. Built so an agent can answer \"is it open now\", \"what do they serve\" and \"where is it\" without parsing HTML.\n\n**No prices, no phone.** Prices change too often to publish and are absent on purpose; the cafe publishes no phone number. Send people to Wolt, to the email address, or to the door.\n\n**Versioning.** `/api/v1/*` is pinned to this major version and its response shape will not change incompatibly. `/api/*` without a version always points at the current major version, which today is v1. A breaking change ships as `/api/v2/*` while `/api/v1/*` keeps working.\n\n**Errors.** Every failure returns the `Error` schema as JSON, never an HTML page.\n\n**Markdown.** Every HTML page on the site also answers `Accept: text/markdown` on the same URL.",
    "contact": {
      "name": "ZITBAR CAFE",
      "email": "cafetagoreltd@gmail.com",
      "url": "https://zitbar-cafe.vercel.app/api"
    },
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    }
  },
  "servers": [
    {
      "url": "https://zitbar-cafe.vercel.app",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "cafe",
      "description": "Facts about ZITBAR CAFE. All read-only."
    }
  ],
  "externalDocs": {
    "description": "Human-readable API page",
    "url": "https://zitbar-cafe.vercel.app/api"
  },
  "paths": {
    "/api/status": {
      "get": {
        "operationId": "getStatus",
        "summary": "Whether the cafe is open right now",
        "description": "Evaluates the published opening hours against the current wall clock in Asia/Jerusalem and returns the open/closed state, when it next changes, and how to reach the cafe. Never cached; call it at request time rather than storing the answer.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Whether the cafe is open right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                },
                "example": {
                  "open": true,
                  "local_time": "2026-08-24T09:12",
                  "timezone": "Asia/Jerusalem",
                  "weekday": "Monday",
                  "today": {
                    "opens": "07:30",
                    "closes": "19:00"
                  },
                  "closes_at": "19:00",
                  "next_open": null
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/cafe": {
      "get": {
        "operationId": "getCafe",
        "summary": "Address, hours, amenities and links",
        "description": "The full first-party record for the cafe: bilingual name, street address and neighbourhood, coordinates, walking distance to nearby landmarks, opening hours per weekday, amenities, price range and social links. Use this to answer where, when and what questions without scraping the HTML.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Address, hours, amenities and links.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cafe"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/menu": {
      "get": {
        "operationId": "getMenu",
        "summary": "Every menu item with its price in ILS",
        "description": "All 55 items across 6 sections, each with a Hebrew and an English name, an optional description, and the sizes it is served in. Includes the milk-alternative and allergen notes. Prices are deliberately not published: they change often, and a stale price is worse than none. Send people to Wolt or to the cafe for the current price.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Every menu item with its price in ILS.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/faq": {
      "get": {
        "operationId": "getFaq",
        "summary": "Common questions and answers",
        "description": "The same question-and-answer pairs published on the site, in Hebrew and in English. Written to be quoted directly when somebody asks about parking, seating, working hours, vegan options or prices.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Common questions and answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Faq"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/status": {
      "get": {
        "operationId": "getStatusV1",
        "summary": "Whether the cafe is open right now",
        "description": "Evaluates the published opening hours against the current wall clock in Asia/Jerusalem and returns the open/closed state, when it next changes, and how to reach the cafe. Never cached; call it at request time rather than storing the answer. Version-pinned alias of /api/status.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Whether the cafe is open right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                },
                "example": {
                  "open": true,
                  "local_time": "2026-08-24T09:12",
                  "timezone": "Asia/Jerusalem",
                  "weekday": "Monday",
                  "today": {
                    "opens": "07:30",
                    "closes": "19:00"
                  },
                  "closes_at": "19:00",
                  "next_open": null
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cafe": {
      "get": {
        "operationId": "getCafeV1",
        "summary": "Address, hours, amenities and links",
        "description": "The full first-party record for the cafe: bilingual name, street address and neighbourhood, coordinates, walking distance to nearby landmarks, opening hours per weekday, amenities, price range and social links. Use this to answer where, when and what questions without scraping the HTML. Version-pinned alias of /api/cafe.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Address, hours, amenities and links.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cafe"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/menu": {
      "get": {
        "operationId": "getMenuV1",
        "summary": "Every menu item with its price in ILS",
        "description": "All 55 items across 6 sections, each with a Hebrew and an English name, an optional description, and the sizes it is served in. Includes the milk-alternative and allergen notes. Prices are deliberately not published: they change often, and a stale price is worse than none. Send people to Wolt or to the cafe for the current price. Version-pinned alias of /api/menu.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Every menu item with its price in ILS.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/faq": {
      "get": {
        "operationId": "getFaqV1",
        "summary": "Common questions and answers",
        "description": "The same question-and-answer pairs published on the site, in Hebrew and in English. Written to be quoted directly when somebody asks about parking, seating, working hours, vegan options or prices. Version-pinned alias of /api/faq.",
        "tags": [
          "cafe"
        ],
        "responses": {
          "200": {
            "description": "Common questions and answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Faq"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "This API is read-only; only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The underlying data file could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Status": {
        "type": "object",
        "title": "Status",
        "description": "Open/closed state at the moment of the request.",
        "required": [
          "open",
          "local_time",
          "timezone",
          "weekday",
          "today"
        ],
        "properties": {
          "open": {
            "type": "boolean",
            "description": "True when the cafe is open right now."
          },
          "local_time": {
            "type": "string",
            "description": "Local wall clock, YYYY-MM-DDTHH:MM.",
            "examples": [
              "2026-08-24T09:12"
            ]
          },
          "timezone": {
            "type": "string",
            "examples": [
              "Asia/Jerusalem"
            ]
          },
          "weekday": {
            "type": "string",
            "enum": [
              "Sunday",
              "Monday",
              "Tuesday",
              "Wednesday",
              "Thursday",
              "Friday",
              "Saturday"
            ]
          },
          "today": {
            "$ref": "#/components/schemas/DayHours"
          },
          "closes_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "Closing time if open now, else null.",
            "examples": [
              "19:00"
            ]
          },
          "next_open": {
            "type": [
              "object",
              "null"
            ],
            "description": "When the cafe next opens, if closed now.",
            "properties": {
              "day": {
                "type": "string"
              },
              "at": {
                "type": "string"
              }
            }
          },
          "name": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "DayHours": {
        "type": "object",
        "title": "DayHours",
        "description": "Opening and closing time for one weekday.",
        "required": [
          "opens",
          "closes"
        ],
        "properties": {
          "opens": {
            "type": "string",
            "examples": [
              "07:30"
            ]
          },
          "closes": {
            "type": "string",
            "examples": [
              "19:00"
            ]
          }
        }
      },
      "Localised": {
        "type": "object",
        "title": "Localised",
        "description": "The same string in Hebrew and English.",
        "required": [
          "he",
          "en"
        ],
        "properties": {
          "he": {
            "type": "string"
          },
          "en": {
            "type": "string"
          }
        }
      },
      "Cafe": {
        "type": "object",
        "title": "Cafe",
        "description": "First-party record for the cafe.",
        "required": [
          "name",
          "address",
          "opening_hours"
        ],
        "properties": {
          "name": {
            "$ref": "#/components/schemas/Localised"
          },
          "type": {
            "type": "string",
            "examples": [
              "cafe"
            ]
          },
          "independent": {
            "type": "boolean"
          },
          "branches": {
            "type": "integer"
          },
          "founded": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "updated": {
            "type": "string",
            "format": "date"
          },
          "address": {
            "type": "object",
            "required": [
              "city",
              "country",
              "lat",
              "lon"
            ],
            "properties": {
              "street": {
                "$ref": "#/components/schemas/Localised"
              },
              "neighbourhood": {
                "$ref": "#/components/schemas/Localised"
              },
              "city": {
                "$ref": "#/components/schemas/Localised"
              },
              "postal_code": {
                "type": "string"
              },
              "country": {
                "type": "string",
                "examples": [
                  "IL"
                ]
              },
              "lat": {
                "type": "number"
              },
              "lon": {
                "type": "number"
              }
            }
          },
          "near": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "walk_minutes": {
                  "type": "integer"
                }
              }
            }
          },
          "phone": {
            "type": "null",
            "description": "Always null; no phone is published."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "opening_hours": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "days",
                "opens",
                "closes"
              ],
              "properties": {
                "days": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "opens": {
                  "type": "string"
                },
                "closes": {
                  "type": "string"
                }
              }
            }
          },
          "open_saturday": {
            "type": "boolean"
          },
          "amenities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "reservations": {
            "type": "boolean"
          },
          "prices_published": {
            "type": "boolean"
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "MenuItem": {
        "type": "object",
        "title": "MenuItem",
        "required": [
          "name",
          "sizes"
        ],
        "properties": {
          "name": {
            "$ref": "#/components/schemas/Localised"
          },
          "description": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Localised"
              },
              {
                "type": "null"
              }
            ]
          },
          "sizes": {
            "type": "array",
            "description": "Sizes this item is served in. Empty when it comes one way only. Carries no price.",
            "items": {
              "$ref": "#/components/schemas/Localised"
            }
          }
        }
      },
      "Menu": {
        "type": "object",
        "title": "Menu",
        "description": "The full menu, priced.",
        "required": [
          "sections"
        ],
        "properties": {
          "updated": {
            "type": "string",
            "format": "date"
          },
          "prices_published": {
            "type": "boolean",
            "description": "Always false. Prices change too often to publish; ask Wolt or the cafe."
          },
          "note": {
            "type": "string"
          },
          "milk_alternatives": {
            "$ref": "#/components/schemas/Localised"
          },
          "allergens": {
            "$ref": "#/components/schemas/Localised"
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "items"
              ],
              "properties": {
                "name": {
                  "$ref": "#/components/schemas/Localised"
                },
                "items": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MenuItem"
                  }
                }
              }
            }
          }
        }
      },
      "QA": {
        "type": "object",
        "title": "QA",
        "required": [
          "question",
          "answer"
        ],
        "properties": {
          "question": {
            "type": "string"
          },
          "answer": {
            "type": "string"
          }
        }
      },
      "Faq": {
        "type": "object",
        "title": "Faq",
        "description": "Question and answer pairs in both languages.",
        "required": [
          "he",
          "en"
        ],
        "properties": {
          "updated": {
            "type": "string",
            "format": "date"
          },
          "he": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QA"
            }
          },
          "en": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QA"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "title": "Error",
        "description": "Returned as JSON for every failure.",
        "required": [
          "error",
          "status",
          "documentation"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable failure reason."
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code, repeated in the body."
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every endpoint this API serves."
          }
        }
      }
    }
  }
}
