Lieferando CLI
Read-only discovery for Lieferando (Just Eat Takeaway) in Germany. The tool is bundled with this skill (zero-dependency Node, needs Node >= 20). Every command prints one JSON envelope: { meta, data, warnings, error? }.
node {baseDir}/scripts/lieferando.mjs <command> [flags]
All examples below use lieferando-cli as shorthand for that invocation.
Hard Limits (tell the user, do not work around)
- This tool CANNOT place orders, log in, or touch payment. There is no such command.
cartcommands are a LOCAL simulation (data.simulation: true); nothing is sent to the platform.- If you get
LFD_BLOCKEDorLFD_RATE_LIMITED, back off. Never retry in a tight loop, never attempt to bypass bot protection. - Ordering itself must be done by the user in the Lieferando app/website. Hand them the restaurant slug and item names.
Location Rules
- Pass
--address "Torstraße 1, 10119 Berlin"(geocoded via OSM, needs street + postcode or city) OR--postcode 10115directly. - Never combine
--addresswith--postcode/--lat/--lng. - German 5-digit postcodes only; primary target is Berlin/Germany.
Providers
- Default:
lieferando. Add--provider ubereatsfor Uber Eats Germany. - Uber Eats specifics: restaurant/store ids are UUIDs from search output (
data.restaurants[].id); the feed only lists currently open stores;min_order_centsis not exposed; item ids from promo carousels rotate, so onLFD_NOT_FOUNDre-runmenuand pick a fresh id from a canonical category;--include-optionsis not supported onmenu(useitem). - Uber Eats
item(option-group detail) hits their most protected endpoint. If it returnsLFD_BLOCKED, stop using that command for at least an hour;search,restaurant, andmenu(which already include item prices) keep working.
Command Selection
- Find restaurants:
lieferando-cli search --postcode 10115 --query "pizza" --open-now --limit 10 --json - Delivery coverage summary:
lieferando-cli availability --postcode 10115 --json - One restaurant (fees, min order, ETA, open state):
lieferando-cli restaurant <slug> --postcode NNNNN --json(without a location only static info is returned) - Full menu:
lieferando-cli menu <slug> --json(add--category "pizza"to narrow,--include-optionsfor option groups inline) - One item with option groups + prices:
lieferando-cli item <slug> <item-id> --json(item ids are UUIDs from menu output) - Local price simulation:
cart add --restaurant <slug> --item <id> [--variant <id>] [--count N] [--options '{"<group-id>":["<option-id>"]}'], thencart preview --postcode NNNNN --json
Prefer menu --category over dumping full menus of large restaurants. Slugs come from search output (data.restaurants[].slug).
Output Parsing
- Read payload from
.data; surface.warningsto the user. - All prices are integer euro cents (
*_cents); divide by 100 for display. - On failure
.error={ code, message, provider, retryable }and exit code is 1 (2 for usage errors). - Retry (once, after a pause) only when
error.retryableis true.
Error Codes
LFD_INVALID_ARGUMENT, LFD_GEOCODE_ERROR, LFD_NOT_FOUND, LFD_RATE_LIMITED (retryable), LFD_UPSTREAM_ERROR (retryable if 5xx), LFD_BLOCKED (stop, do not retry), LFD_NETWORK_ERROR (retryable), LFD_CART_ERROR, LFD_UNSUPPORTED_LOCATION.
Example Workflow
lieferando-cli search --postcode 10115 --query sushi --open-now --json→ pick a slug by rating/fee/ETA.lieferando-cli menu <slug> --category maki --json→ pick item ids.lieferando-cli item <slug> <item-id> --json(item ids are UUIDs from menu output) → resolve required option groups (min_choices >= 1).- Optionally simulate cost with
cart add+cart preview. - Give the user the restaurant name, items, and estimated total; they order themselves.
