Menudata API
Overview
Section titled “Overview”The Menudata API provides a daily export of posts.
The API is designed for bulk delivery:
- You call the API endpoint.
- It returns a signed download URL.
- You download the export file from that URL.
Authentication
Section titled “Authentication”This endpoint requires an API key.
Send one of:
- Preferred:
Authorization: Bearer <YOUR_API_KEY> - Alternative:
x-api-key: <YOUR_API_KEY>
If the key is missing or invalid, the API returns 401.
Endpoints
Section titled “Endpoints”GET /v1/menudata
Section titled “GET /v1/menudata”Returns a signed download URL for the daily export file.
Example request
Section titled “Example request”curl -sS "https://menudata-api-794349016039.us-east4.run.app/v1/menudata" \ -H "Authorization: Bearer YOUR_API_KEY"Example response
Section titled “Example response”{ "ok": true, "durationMs": 12345, "expiresAt": "2025-12-18T23:53:01.344Z", "downloadUrl": "https://storage.googleapis.com/<bucket>/<path>?X-Goog-..."}Fields
downloadUrl: signed URL (temporary) to download the export file.expiresAt: when the signed URL will expire (request a new URL after expiration).
GET /v1/brands
Section titled “GET /v1/brands”Returns a signed download URL for a daily export of recent Instagram posts from a curated list of top food and beverage brands, enriched with analysis fields (including topic and format fields when available).
Example request
Section titled “Example request”curl -sS "https://menudata-api-794349016039.us-east4.run.app/v1/brands" \ -H "Authorization: Bearer YOUR_API_KEY"Example response
Section titled “Example response”{ "ok": true, "exportMode": "gcs", "durationMs": 12345, "cacheHit": false, "objectPath": "menudata/brands/2026-02-13.ndjson.gz", "expiresAt": "2026-02-13T23:53:01.344Z", "downloadUrl": "https://storage.googleapis.com/<bucket>/<path>?X-Goog-..."}Behavior
- Daily cache key: one export artifact per UTC date. Repeated requests on the same UTC day return the same file (
cacheHit: true). - First request with no prior successful export: bootstrap window is the last 24 hours.
- Subsequent day requests: delta window starts at the previous successful export watermark and ends at the current request time.
- If no requests were made for multiple days: the next request spans the full gap since the last successful export (not limited to 24 hours).
- Cutoff semantics: posts are included when
timestamp > exportFromTsandtimestamp <= exportToTs. - Local mode note: in
MENUDATA_EXPORT_MODE=local,/v1/brandsalways uses a fresh 24-hour bootstrap window and writes a local file instead of creating a GCS daily artifact.
GET /v1/flavors
Section titled “GET /v1/flavors”Returns the list of supported flavors for validation and discovery.
Example request
Section titled “Example request”curl -sS "https://menudata-api-794349016039.us-east4.run.app/v1/flavors" \ -H "Authorization: Bearer YOUR_API_KEY"Example response
Section titled “Example response”{ "ok": true, "count": 92, "flavors": ["Acai", "Agave", "Almond Milk"]}GET /v1/flavors/search
Section titled “GET /v1/flavors/search”Runs the flavor search pipeline (multi-index + rerank) and returns a signed download URL for the daily export of posts that match the flavor.
Query params
Section titled “Query params”flavor(required): must exactly match a value returned byGET /v1/flavors.
Example request
Section titled “Example request”curl -sS "https://menudata-api-794349016039.us-east4.run.app/v1/flavors/search?flavor=Carrot" \ -H "Authorization: Bearer YOUR_API_KEY"Example response
Section titled “Example response”{ "ok": true, "durationMs": 12345, "expiresAt": "2025-12-18T23:53:01.344Z", "downloadUrl": "https://storage.googleapis.com/<bucket>/<path>?X-Goog-..."}Notes
- Responses are cached per flavor per UTC day; repeated requests return the same export.
- Results are filtered to rerank scores 4–5 and a minimum of 10k likes.
Downloading & reading the export
Section titled “Downloading & reading the export”The export is NDJSON (one JSON object per line).
The object is stored in GCS as gzip-compressed (.ndjson.gz), but depending on your HTTP client, the download response may be automatically decompressed; if gunzip fails, treat the response as plain NDJSON.
Download the file
Section titled “Download the file”curl -L -o menudata.ndjson.gz "$DOWNLOAD_URL"Read the first few rows (works even if the response is auto-decompressed)
Section titled “Read the first few rows (works even if the response is auto-decompressed)”curl -sSL "$DOWNLOAD_URL" | head -n 5Read the first few rows
Section titled “Read the first few rows”gunzip -c menudata.ndjson.gz | head -n 5Convert to JSON array (optional)
Section titled “Convert to JSON array (optional)”If you need an array instead of NDJSON:
gunzip -c menudata.ndjson.gz | jq -s '.' > menudata.json- The signed URL is temporary. If it expires, call
GET /v1/menudataagain to get a new one.