Developers

Menumigo for developers and AI agents

Everything on this page is public, read-only and unauthenticated. There is no API key to request, no account to create, no sandbox to be granted — the examples below run against production and are safe to paste into a terminal right now. Responses are CORS-open, so browser-based agents can fetch them cross-origin.

curl -s https://menumigo.com/api/public | head -40

Quickstart

Three requests cover most integrations: find a restaurant, read its menu, read the plan limits. Authentication is not part of any of them.

1. Find a restaurant

curl -s "https://menumigo.com/api/public/restaurants?q=cafe&city=Lisbon&limit=3"

Each result carries the slug you need next, plus url, markdownUrl and apiUrl so you never have to build a URL by hand.

2. Read the full menu

curl -s https://menumigo.com/api/public/restaurants/portovibe-cafe

Returns categories and items with prices, currency, availability, dietary tags, the fourteen EU allergens, nutrition, variants, and translations keyed by language code. Serialization is an explicit allowlist, so no account or owner data is ever exposed.

3. Read the plan limits

curl -s https://menumigo.com/api/public/plans

A null limit means unlimited. Prices are in EUR.

Endpoint reference

The authoritative machine-readable version is openapi.json (OpenAPI 3.1). Everything below is a GET unless noted.

GET/api/public

Index of the API itself: every endpoint, its parameters, and the error format.

curl -s "https://menumigo.com/api/public"

GET/api/public/restaurants

Search published restaurants.

q
Free-text match on name, description or slug.
city
Case-insensitive city filter.
cuisine
Case-insensitive cuisine filter.
limit
1–50, default 20. Values outside the range are clamped.
curl -s "https://menumigo.com/api/public/restaurants?city=Lisbon&limit=5"

GET/api/public/restaurants/{slug}

One restaurant's profile and complete menu: categories, items, prices, currency, EU-14 allergens, dietary tags, opening hours, ratings and per-language translations.

slug
The identifier in the public menu URL, menumigo.com/{slug}.
curl -s "https://menumigo.com/api/public/restaurants/portovibe-cafe"

GET/api/public/locations

Every country and city directory page, with its canonical URL.

curl -s "https://menumigo.com/api/public/locations"

GET/api/public/cuisines

Every cuisine and venue-type page, with its canonical URL.

curl -s "https://menumigo.com/api/public/cuisines"

GET/api/public/plans

Plans, prices and the exact limits the product enforces. Read from the same module the billing code gates on, so it cannot drift from what is actually charged.

curl -s "https://menumigo.com/api/public/plans"

GET, POST/api/public/tools/food-cost

Portion cost, waste buffer, labour overhead, gross margin, suggested price and a plain-language recommendation.

cost
Raw ingredient cost for one portion (GET).
margin
Target gross margin percentage, default 70 (GET).
price
Current selling price, to analyse the existing margin (GET).
body
POST accepts JSON with ingredients[] ({name, quantity, unitCost} or {cost}), wastePercentage and laborOverheadPercentage.
curl -s "https://menumigo.com/api/public/tools/food-cost?cost=4.20&margin=70&price=14"

GET/api/public/tools/wifi-qr

Wi-Fi QR payload in the WIFI:S:…;T:WPA;P:…;; format, with per-platform connection instructions.

ssid
Required. Network name.
password
Ignored when encryption=nopass.
encryption
WPA (default), WEP or nopass.
hidden
true for a hidden SSID.
curl -s "https://menumigo.com/api/public/tools/wifi-qr?ssid=Cafe%20Guest&password=hello123"

GET/api/public/tools/review-qr

Google review target URL and QR payload for a venue.

placeId
Google Place ID. Either this or url is required.
url
A direct Google review URL, used as-is.
curl -s "https://menumigo.com/api/public/tools/review-qr?placeId=ChIJN1t_tDeuEmsRUsoyG83frY4"

Error format

Every failure under /api is JSON — including a request to a path that does not exist. You never get an HTML error page from the API, so a parser can rely on the shape. Errors are sent with Cache-Control: no-store.

$ curl -s https://menumigo.com/api/public/restaurants/no-such-venue

{
  "error": "not_found",
  "status": 404,
  "message": "No public menu for slug \"no-such-venue\". Either no restaurant
              uses that slug, or its menu is not published.",
  "hint": "Search for the restaurant with
           https://menumigo.com/api/public/restaurants?q=no-such-venue and use the
           `slug` from the result.",
  "documentation": "https://menumigo.com/developers",
  "specification": "https://menumigo.com/openapi.json"
}

Branch on error — it is a stable code and will not be renamed. message describes what happened and hint describes the fix. A 404 on an unknown path also carries availableEndpoints, so a mistyped URL corrects itself in one round trip.

CodeStatusMeaning
not_found404No endpoint at that path, or no published resource with that identifier.
invalid_request400A required parameter is missing or malformed.
invalid_json400The POST body could not be parsed as JSON.
method_not_allowed405The endpoint exists but not for that method. Allow lists what it takes.
not_acceptable406None of the media types in your Accept header can be produced.
rate_limited429Too many requests; back off and retry.
internal_error500Something failed on our side. Safe to retry.

Markdown content negotiation

Every public page is served in two representations at one URL. Ask for Markdown with an Accept header, or append .md to the path — both return the same chrome-free document with YAML front matter and no navigation, scripts or styling.

curl -s -H "Accept: text/markdown" https://menumigo.com/pricing
curl -s https://menumigo.com/pricing.md          # same bytes, explicit URL
curl -s https://menumigo.com/index.md            # the home page

This follows the acceptmarkdown.com convention: responses carry Content-Type: text/markdown; charset=utf-8 and Vary: Accept, q-values are honoured (including q=0 as an explicit rejection), and a request that accepts none of text/html or text/markdown gets a 406 listing what is available rather than a silent fallback.

The complete list of Markdown pages is at /llms-index.md, generated from the route table rather than maintained by hand. Every HTML page also declares its twin with <link rel="alternate" type="text/markdown">, and every Markdown response points back with a Link: …; rel="canonical" header.

MCP server

Menumigo runs a remote Model Context Protocol server over HTTP JSON-RPC 2.0 at https://menumigo.com/api/mcp. It needs no credentials, so it can be added to any MCP client as a plain URL.

curl -s -X POST https://menumigo.com/api/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
ToolDoes
search_restaurantsSearch published restaurants by name, cuisine, city or keyword.
get_restaurant_menuFull menu, prices, allergens, dietary tags and contact details for a slug.
calculate_food_costDish cost, margin, target price and profitability recommendations.
generate_wifi_qr_payloadWi-Fi QR payload for a guest network.
generate_review_qr_payloadGoogle review URL and QR payload.
get_menumigo_plansPlans, prices and enforced limits.
list_locations_and_cuisinesThe full location and cuisine directory.

initialize, tools/list, tools/call, resources/list and resources/read are supported. The manifest is at /.well-known/mcp.json.

Machine-readable manifests

Every discovery file this site publishes, in one place:

/openapi.json
OpenAPI 3.1 specification for every endpoint below.
/.well-known/mcp.json
MCP server manifest.
/.well-known/ai-plugin.json
AI plugin manifest.
/.well-known/agent.json
Agent discovery manifest: indexes, API map, Markdown pattern.
/.well-known/security.txt
Security contact and disclosure policy.
/llms.txt
Site overview written for agents.
/llms-full.txt
Full reference: every URL, feature and FAQ.
/llms-index.md
Every Markdown page, generated from the route table.
/sitemap.xml
Canonical HTML URLs.

Public restaurant menus additionally embed schema.org Restaurant + Menu JSON-LD, with hasMenuSection and hasMenuItem down to prices and allergens.

Limits, caching and terms

  • No authentication, no quota registration. Please stay reasonable — cache responses and avoid hammering search. There is no published quota today; if throttling ever becomes necessary it will be announced here and returned as error: "rate_limited" with a 429, never as a silent failure.
  • Cacheable by design. Directory and plan data carry a 24-hour s-maxage, restaurant search 60 seconds, and a single menu 5 minutes. Errors are never cached.
  • Read-only. There is no write API. Menus are edited by their owners in the dashboard. Non-GET requests to a read endpoint return 405 with an Allow header.
  • No personal data. The API exposes only what is already published on the public menu pages — no account data, no guest data, no analytics.
  • Attribution. Data is provided for informational use with attribution to menumigo.com. Use is subject to our terms of service.

Something missing, or an endpoint you need? Tell us — the API is small on purpose and grows on request.