{
  "openapi": "3.1.0",
  "info": {
    "title": "KAMI Sushi & Poké ordering helper",
    "version": "1.0.0",
    "description": "Read-only endpoints that let an AI assistant prepare an order at KAMI Sushi & Poké (Paje, Zanzibar) for a person. Nothing is placed server-side: the response contains a pre-filled, priced WhatsApp link (whatsapp_url) and a pre-filled cart link for the KAMI ordering app (cart_url). The person opens one and presses send. Prices are live from the KAMI Ledger, in Tanzanian shillings (TZS). Open Monday to Saturday 13:00-22:00 Zanzibar time (UTC+3), last orders 21:30, closed Sunday. Guide: https://sushi.yapyap.us/llms.txt",
    "contact": {
      "name": "KAMI Sushi & Poké",
      "email": "sushi@yapyap.us",
      "url": "https://sushi.yapyap.us"
    }
  },
  "servers": [
    {
      "url": "https://kami-sushi-worker.michael-594.workers.dev"
    }
  ],
  "security": [],
  "paths": {
    "/api/menu-for-ai": {
      "get": {
        "operationId": "getMenu",
        "summary": "Live menu with item ids, options, order tokens and prices (TZS)",
        "description": "Call this first. Every orderable choice has a token (e.g. hoso-maki:size=8:fill=salmon) to pass to /api/order-link as item=<token>:qty=N. Prawns are always available wherever salmon is, at the salmon price.",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "text"
              ],
              "default": "json"
            },
            "description": "text returns a plain-text menu"
          }
        ],
        "responses": {
          "200": {
            "description": "Menu",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "503": {
            "description": "Live menu temporarily unavailable"
          }
        }
      }
    },
    "/api/order-link": {
      "get": {
        "operationId": "buildOrderLink",
        "summary": "Validate and price an order; returns a WhatsApp link the person sends",
        "description": "Example: https://kami-sushi-worker.michael-594.workers.dev/api/order-link?item=sashimi:fish=tuna:qty=2&item=fries&mode=pickup&name=Anna . whatsapp_url is only returned when ok is true. Show the person the lines and total, then give them whatsapp_url (or cart_url).",
        "parameters": [
          {
            "name": "item",
            "in": "query",
            "required": true,
            "style": "form",
            "explode": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "One per order line: id:axis=option:axis=option:qty=N:note=text . Every axis of the item must be chosen. A bare option id (hoso-maki:8:salmon) also works; a bare number that is not an option is the quantity. note= must come last and may contain colons.",
            "examples": {
              "simple": {
                "value": [
                  "sashimi:fish=tuna:qty=2",
                  "fries"
                ]
              },
              "withNote": {
                "value": [
                  "chirashi:fill=prawns:qty=2:note=no sesame"
                ]
              }
            }
          },
          {
            "name": "items",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Alternative to repeated item: comma-separated lines (no commas inside notes)."
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pickup",
                "delivery"
              ],
              "default": "pickup"
            }
          },
          {
            "name": "zone",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "paje",
                "bwejuu",
                "jambiani",
                "dongwe",
                "michamvi",
                "makunduchi",
                "stone-town",
                "airport"
              ]
            },
            "description": "Delivery reference point. Or send lat and lng for an exact fee."
          },
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Delivery drop-off latitude (Unguja island)"
          },
          {
            "name": "lng",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Delivery drop-off longitude"
          },
          {
            "name": "address",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Required for delivery: hotel, villa or beach bar name, room"
          },
          {
            "name": "name",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 60
            },
            "description": "Customer first name"
          },
          {
            "name": "phone",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Optional WhatsApp number with country code"
          },
          {
            "name": "when",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "asap"
            },
            "description": "asap | hour | HH:MM (today) | YYYY-MM-DD HH:MM, Zanzibar time (UTC+3). Monday to Saturday 13:00-21:30 (last orders 30 minutes before closing)."
          },
          {
            "name": "people",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "4",
                "5+"
              ],
              "default": "1"
            }
          },
          {
            "name": "notes",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Allergies, table, sunbed, anything else"
          },
          {
            "name": "lang",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "pl",
                "da",
                "it",
                "de",
                "fr",
                "sw"
              ],
              "default": "en"
            },
            "description": "Language of the app opened by cart_url. The WhatsApp message is always English."
          }
        ],
        "responses": {
          "200": {
            "description": "Valid order",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderLink"
                }
              }
            }
          },
          "422": {
            "description": "Invalid order; see errors (whatsapp_url is null)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderLink"
                }
              }
            }
          },
          "503": {
            "description": "Live menu temporarily unavailable"
          }
        }
      },
      "post": {
        "operationId": "buildOrderLinkJson",
        "summary": "Same as GET, with a JSON body",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderRequest"
              },
              "example": {
                "items": [
                  {
                    "id": "rainbow",
                    "options": {
                      "size": "8",
                      "fish": "salmon"
                    },
                    "qty": 1
                  },
                  {
                    "id": "chirashi",
                    "options": {
                      "fill": "prawns"
                    },
                    "qty": 2,
                    "note": "no sesame"
                  }
                ],
                "mode": "delivery",
                "zone": "jambiani",
                "address": "Coral Rock Hotel room 3",
                "name": "Tom",
                "phone": "+45 12 34 56 78",
                "when": "19:30",
                "people": "3"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Valid order",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderLink"
                }
              }
            }
          },
          "400": {
            "description": "Body is not JSON"
          },
          "422": {
            "description": "Invalid order; see errors",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderLink"
                }
              }
            }
          },
          "503": {
            "description": "Live menu temporarily unavailable"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Variant": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "examples": [
              "hoso-maki:size=8:fill=salmon"
            ]
          },
          "label": {
            "type": "string"
          },
          "price": {
            "type": "integer",
            "description": "TZS"
          }
        }
      },
      "MenuItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "vegan_possible": {
            "type": "boolean"
          },
          "raw": {
            "type": "boolean"
          },
          "price": {
            "type": "integer",
            "description": "TZS, for items without options"
          },
          "token": {
            "type": "string"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "choices": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "label": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variant"
            }
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "Menu": {
        "type": "object",
        "properties": {
          "restaurant": {
            "type": "string"
          },
          "currency": {
            "const": "TZS"
          },
          "updated": {
            "type": "string",
            "format": "date-time"
          },
          "source": {
            "type": "string"
          },
          "rules": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "how_to_order": {
            "type": "object"
          },
          "delivery": {
            "type": "object"
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "items": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MenuItem"
                  }
                }
              }
            }
          }
        }
      },
      "OrderRequest": {
        "type": "object",
        "required": [
          "items",
          "name"
        ],
        "properties": {
          "items": {
            "type": "array",
            "maxItems": 40,
            "items": {
              "oneOf": [
                {
                  "type": "string",
                  "description": "Same line format as the GET item parameter"
                },
                {
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "options": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      },
                      "description": "axis key -> option id"
                    },
                    "qty": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 50,
                      "default": 1
                    },
                    "note": {
                      "type": "string",
                      "maxLength": 200
                    }
                  }
                }
              ]
            }
          },
          "mode": {
            "type": "string",
            "enum": [
              "pickup",
              "delivery"
            ],
            "default": "pickup"
          },
          "zone": {
            "type": "string",
            "enum": [
              "paje",
              "bwejuu",
              "jambiani",
              "dongwe",
              "michamvi",
              "makunduchi",
              "stone-town",
              "airport"
            ]
          },
          "lat": {
            "type": "number"
          },
          "lng": {
            "type": "number"
          },
          "address": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "when": {
            "type": "string",
            "default": "asap"
          },
          "people": {
            "type": "string",
            "enum": [
              "1",
              "2",
              "3",
              "4",
              "5+"
            ]
          },
          "notes": {
            "type": "string"
          },
          "lang": {
            "type": "string"
          }
        }
      },
      "OrderLink": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "options": {
                  "type": "object"
                },
                "meta": {
                  "type": "string"
                },
                "token": {
                  "type": "string"
                },
                "qty": {
                  "type": "integer"
                },
                "unit_price": {
                  "type": "integer"
                },
                "line_total": {
                  "type": "integer"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "subtotal": {
            "type": "integer"
          },
          "delivery_fee": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "currency": {
            "const": "TZS"
          },
          "mode": {
            "type": "string",
            "enum": [
              "pickup",
              "delivery"
            ]
          },
          "delivery": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "zone": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "lat": {
                "type": "number"
              },
              "lng": {
                "type": "number"
              },
              "distance_km": {
                "type": "number"
              },
              "fee": {
                "type": "integer"
              },
              "in_paje": {
                "type": "boolean"
              },
              "source": {
                "type": "string"
              }
            }
          },
          "when": {
            "type": "string"
          },
          "whatsapp_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "wa.me link with the full order message; the person opens it and presses send"
          },
          "cart_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opens https://sushi.yapyap.us/mobile/ with the cart filled in"
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "The WhatsApp message text"
          },
          "instructions": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "item": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "message": {
                  "type": "string"
                },
                "valid_options": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Variant"
                  }
                },
                "valid_zones": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "label": {
                        "type": "string"
                      },
                      "approx_fee": {
                        "type": "integer"
                      }
                    }
                  }
                }
              },
              "required": [
                "message"
              ]
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "ok",
          "lines",
          "subtotal",
          "delivery_fee",
          "total",
          "currency",
          "whatsapp_url",
          "cart_url",
          "errors"
        ]
      }
    }
  }
}
