Lidl-Reisen: unofficial search API (GraphQL) for trip/price scans
Last updated 05/11/2026 · travel, api, web, booking, lidl
Endpoints (de; AT/CH have their own hosts, discover via $ENV in the page HTML)
The Angular app shell at https://www.lidl-reisen.de/... embeds a $ENV={...} block with every base URL:
- Search GraphQL:
https://search-api-mvp2prod.lidl-reisen.de/graphql— no auth, introspection enabled (query { __schema { types { name } } }). - Product REST:
https://product-api-mvp2prod.lidl-reisen.de/product/{productId}/journey?offer-id=<oId>&adult-count=2plus/accommodation,/accommodation/{tourOperator},/destination,/included-services,/service-extras. Needs headerapplication-domain: Lidl_de_DE(valid:Lidl_de_DE|Lidl_de_AT|Lidl_de_CH). - Booking / payment / rating:
booking-api-mvp2prod.lidl-reisen.de,travel-payment-api.mvp2prd.sit.sys.odj.cloud,travel-accommodation-rating-api.mvp2prd.sit.sys.odj.cloud(booking not tested).
Copy-paste probe:
curl -sS -X POST https://search-api-mvp2prod.lidl-reisen.de/graphql \
-H 'Content-Type: application/json' -H 'application-domain: Lidl_de_DE' \
-d '{"query":"query { travelSearchResults(destination:\"Hurghada\", adultCount:2, dateFrom:\"2026-11-22\", dateTo:\"2026-12-06\", minTravelDuration:7, maxTravelDuration:7, departureAirports:[\"FRA\"], selectedFilter:[\"All-Inclusive\",\"Direktflug\",\"Doppelzimmer\"], orderBy: PRICE_TOTAL_ASCENDING, resultLimit:10) { totalResults searchResult { productId accommodation { title stars } fromPrice { priceTotal pricePerson } } } }"}'
GraphQL root fields (on TravelSearch)
| Field | Use |
|---|---|
travelSearchResults |
product/destination search; args incl. destination, freeText, productIds, departureAirports, dateFrom/dateTo, minTravelDuration/maxTravelDuration, adultCount, childrenAges, selectedFilter, minPriceTotal/maxPriceTotal, minAccommodationRating, orderBy, resultLimit, category |
offerSearchResults |
all offers for one productId → GroupedTravelOffers { groupName, groupType, offers[...] } |
offerAvailableTravelDates |
the price calendar (isBestPrice, fromDate, offerId, price) |
offerAvailableTravelDurations |
cheapest price per duration for a window |
filterResults |
list of valid selectedFilter tags + match counts |
travelSearchSurroundingResults |
hotels near a product |
availableAirportSearchResults |
airports that actually serve a product (requires **productId**) |
travelSearchAlternativeRequests, travelSearchAlternativeProducts, destinationSuggestResults, teaserSearchResult |
misc |
Enums: SearchResultOrderBy = BEST_OFFERS_FIRST, PRICE_TOTAL_ASCENDING, PRICE_TOTAL_DESCENDING, PRICE_PER_NIGHT_ASCENDING, PRICE_PER_PERSON_ASCENDING; DealType = ALL, ONLY_TOP_DEALS, ONLY_NON_TOP_DEALS; SearchRouteType = HOTEL, CITY, REGION, COUNTRY, DEPARTURE_AIRPORT, ARRIVAL_AIRPORT, ...; OfferLiteGroupBy = NONE, ROOM_TITLE.
Object shapes: TravelProduct → productId, accommodation, offerInformation, travelInformation, inclusiveServices, tourOperator, traveller, travelDate, roomBoard, fromPrice. Price → priceTotal, pricePerson, priceDiscountTotal, currency, isOfferSourcePrice. AccommodationRating → rating, recommendation, reviewCount, ratingType.
Gotchas
fromPrice/priceare lists of Price objects, not objects.selectedFiltervalues are the literal German tag strings from the URLtags=param (All-Inclusive,Direktflug,Doppelzimmer,Strand,Rail & Fly, …) — get the full list fromfilterResults.- Prices are live: they moved by ~30 € within minutes during one session. Always timestamp a snapshot.
travelInformation.departureAirport.airportCodeoften returnsTBAintravelSearchResults; unknown codes silently fall back (e.g.TXL→ FRA). UseofferSearchResultsfor per-offer airport accuracy.InclusiveServiceobjects have onlydescription/isIncluded/until— there is nonamefield.- Duration levers: shorter trips are cheaper in absolute terms but worse per night; the sweet spot for Sentido Naga Bay was 7 nights (~200 €/night).
minTravelDuration/maxTravelDurationcan be a range in one call. - In
offerAvailableTravelDates,priceTotalis 0 — usepricePerson. - In every search,
dateFrom/dateTobound the departure date, not the return. To enforce “back by X”, filter results ontravelDate.dateTo <= Xclient-side. travelSearchResultswith onlyproductIds(no dates) returns arbitrary default offers.robots.txtfor *.de is self-contradictory (Allow: /thenDisallow: /) — keep request volume low and personal.
Scanner script
Kept in the KB repo so every host has it after mem sync: <kb>/bin/lidl-reisen.py (/data/ai-persistence/bin/lidl-reisen.py on metis/iris/handtrixxx.com, /home/handtrixxx/code/ai-persistence/bin/lidl-reisen.py on the ThinkPad; also /home/handtrixxx/code/lidl-reisen/lidl_api.py). Stdlib only, verified working 2026-10-28:
./lidl_api.py find --destination Hurghada --from 2026-11-22 --to 2026-12-06 --nights 7 \
--airport FRA --filter All-Inclusive --filter Direktflug --filter Doppelzimmer --max-price 2100
./lidl_api.py compare --id PA-1423030 --from 2026-11-22 --to 2026-12-06 --nights 7 --filter All-Inclusive # cheapest per departure airport
./lidl_api.py search --id PA-1423030 --from 2026-11-22 --to 2026-12-06 --nights 7 --airport BER # offers for one product
./lidl_api.py calendar --id PA-1423030 --from 2026-11-22 --to 2027-03-31 --nights 7 --airport BER
./lidl_api.py flex --id PA-1423030 --from 2026-11-16 --to 2026-12-06 --min-nights 5 --max-nights 12 --filter All-Inclusive
./lidl_api.py product --id PA-1423030
./lidl_api.py airports --id PA-1423030 --from 2026-11-22 --to 2026-12-06 --nights 7
--airport is repeatable and optional: omitting it queries all served airports, and flex/compare restrict their per-airport scan to the codes given (fixed 2026-10-28; previously flex ignored --airport).
Reference case (Niklas’ Hurghada trip, snapshot 2026-10-28)
PA-1423030= Sentido Naga Bay Resort & Spa, Sharm el Naga south of Hurghada, 5★, ~766 HolidayCheck reviews; operators ITS / DERTOUR / Travelix (same inventory as DERTOUR — compare there too).- Baseline 22.11.–06.12.2026, 7 nights, 2 adults, Doppelzimmer Deluxe Meerblick, all-inclusive, direct flight: FRA ~1.780 € total, BER ~1.446 €, BSL ~1.402 €, MUC/ZRH ~1.560 €.
- Flexible window 16.11.–06.12.2026 (arrive by 06.12.), 7 nights / AI / direct / Doppelzimmer, cheapest per airport: BSL 1.402 € (27.11.–04.12.), BER 1.446 € (26.11.–03.12.), GVA 1.450 €, LEJ 1.492 €, MUC/ZRH 1.560 €, HAM 1.590 €, STR 1.604 €, FRA 1.780 €. Absolute cheapest of any duration: 5 nights BER 1.178 € (28.11.–03.12.) at ~236 €/night — worse per night than the 7-night BSL deal (~200 €/night).
- Cheapest levers, in order: departure airport (up to ~380 €), date shift, dropping
Direktflug(~320 € cheaper from FRA but verify stopover in UI).
Niklas’ Hurghada constraint set (fixed 2026-10-28)
Product PA-1423030 (Sentido Naga Bay Resort & Spa), 2 adults, min 7 nights, return to Germany latest 06.12.2026, departure airports limited to NUE / HAJ / FRA (Erfurt not offered — departureAirports:["ERF"] → totalResults: 0; LEJ Leipzig/Halle is the closest served airport to Erfurt, ~130 km). Canonical scan:
./lidl_api.py flex --id PA-1423030 --from 2026-11-16 --to 2026-12-06 --min-nights 7 --max-nights 12 \
--airport NUE --airport HAJ --airport FRA --filter All-Inclusive --filter Direktflug --filter Doppelzimmer
Best direct-flight 7-night prices (snapshot 2026-10-28, re-runs the same day gave FRA 1.478–1.780 € — prices move by hundreds of euros within hours, so timestamp every snapshot and re-scan before booking): NUE 1.602 € (28.11.–05.12.), FRA 1.780 € (27.11.–04.12.), HAJ 1.810 € (27.11.–04.12.). Prices rise steeply earlier in the window (NUE 16.11. = 2.680 €); the sweet spot is the last week of November. Per-night is better with longer stays while still returning by 06.12.: LEJ 10N 1.922 € (192 €/N), NUE 10N 2.072 € (207 €/N), NUE 9N 1.896 € (211 €/N). Dropping Direktflug is ~190 € cheaper (NUE/HAJ 7N 1.410 €) but the flight then has a stopover — confirm in the UI before booking. --links prints the booking deep link for each best offer (.../product/PA-1423030/details?...&dep=<airport>&durMin=N&durMax=N&oId=<url-encoded offerId>), which opens the exact offer in the web UI.
Departure airports Lidl-Reisen actually serves
35 for PA-1423030 (Hurghada, 4–12 nights, verified 2026-10-28): AMS, BER, BRE, BRU, BSL, BTS, BUD, CGN, CLJ, CPH, CRL, DRS, DTM, DUS, EIN, FMO, FRA, GRZ, GVA, HAJ, HAM, KTW, LEJ, LNZ, LUX, MUC, NUE, PRG, RTM, SOF, STR, SZG, VIE, WRO, ZRH. The list is per product and per date window — always fetch it with availableAirportSearchResults instead of guessing. Kassel (KSN) is not offered (verified 2026-10-28): departureAirports:["KSN"] → totalResults: 0, and KSN never appears in any airport list. destinationSuggestResults(term:"Kassel") only returns Kassel as a destination (124 docs) and as category: ARRIVAL_AIRPORT (7 docs) — those are self-drive/bus hotel stays with departureAirport: null or TBA, never flights. For someone near Kassel the practical airports are FRA (~80 km), HAJ (~130 km), NUE (~150 km), DUS/STR (~180–200 km).
- Same-area alternatives: Viva Blue Resort & Diving Sharm El Naga (4★) ~1.374 €, Siva Golden Bay Makadi ~1.236 €, JAZ Soma Beach ~1.702 €.
- All snapshots above are 2026-10-28; re-run
compare/findbefore deciding.
Source: Wiki.js