{"description":"Finds Deutsche Bahn connections (ICE, IC, regional, S-Bahn, bus) like bahn.de's own search: departure and arrival times, duration, transfers, trains with platforms, and the cheapest fare ('ab' price) for the chosen class. Station names are free text; the first station match is used and returned. Runs only inside the user's browser: bahn.de's Akamai protection rejects every request without the browser's own cookies.","effect":"read","id":"bahn.de/search-connections","keywords":["bahn","deutsche bahn","db","zug","zugverbindung","fahrplan","verbindung suchen","ice","fahrkarte","ticketpreis","train","train connection","timetable","rail","ticket price","germany train"],"output":{"schema":{"properties":{"connections":{"items":{"properties":{"arrival":{"type":"string"},"arrival_realtime":{"type":["string","null"]},"currency":{"type":["string","null"]},"departure":{"description":"Scheduled, Europe/Berlin local, YYYY-MM-DDTHH:mm:ss","type":"string"},"departure_realtime":{"description":"Real-time forecast, only close to departure","type":["string","null"]},"duration_min":{"type":["integer","null"]},"from":{"type":"string"},"legs":{"items":{"properties":{"arrival":{"type":"string"},"arrival_platform":{"type":["string","null"]},"category":{"type":"string"},"departure":{"type":"string"},"departure_platform":{"type":["string","null"]},"direction":{"type":["string","null"]},"from":{"type":"string"},"to":{"type":"string"},"train":{"type":"string"}},"type":"object"},"type":"array"},"price_class":{"type":["string","null"]},"price_eur":{"description":"Cheapest fare for this connection, class and travellers ('ab' price, Sparpreis if available). null when bahn.de shows no price","type":["number","null"]},"to":{"type":"string"},"trains":{"description":"e.g. ['ICE 1005']","items":{"type":"string"},"type":"array"},"transfers":{"type":"integer"}},"type":"object"},"type":"array"},"date":{"format":"date","type":"string"},"from":{"description":"Departure station actually used (first station match for params.from)","type":"string"},"next_page_ref":{"description":"Pass as page_ref (with the same other params) to get later connections","type":["string","null"]},"to":{"description":"Arrival station actually used","type":"string"}},"required":["from","to","date","connections"],"type":"object"},"value":"{from: steps.from_station.name, to: steps.to_station.name, date: params.date, connections: steps.search.connections, next_page_ref: steps.search.later_ref}"},"params":{"additionalProperties":false,"properties":{"adults":{"default":1,"description":"Number of adult travellers without discount card","maximum":9,"minimum":1,"type":"integer"},"date":{"description":"Travel date YYYY-MM-DD","pattern":"^\\d{4}-\\d{2}-\\d{2}$","type":"string"},"from":{"description":"Departure station, e.g. 'Berlin Hbf', 'Hamburg'","maxLength":80,"minLength":2,"type":"string"},"mode":{"default":"ABFAHRT","description":"ABFAHRT = depart at or after time, ANKUNFT = arrive by time","enum":["ABFAHRT","ANKUNFT"],"type":"string"},"page_ref":{"description":"next_page_ref from a previous result, to get later connections with otherwise identical params","maxLength":2000,"type":"string"},"time":{"default":"08:00","description":"HH:mm, Europe/Berlin local time","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","type":"string"},"to":{"description":"Arrival station, e.g. 'München Hbf'","maxLength":80,"minLength":2,"type":"string"},"travel_class":{"default":"KLASSE_2","description":"2nd or 1st class (changes the price)","enum":["KLASSE_2","KLASSE_1"],"type":"string"}},"required":["from","to","date"],"type":"object"},"provenance":{"method":"browser-inspect","notes":"spikes/bahn.md. Akamai Bot Manager: every /web/api call without the browser's own _abck/bm_sz cookies gets 403 OPS_BLOCKED (curl, credentials:'omit'). Automated browsers (Playwright, Claude browser pane) also get 403 on fahrplan, so this recipe can only be verified in a human-driven Chrome with the extension (tests/e2e/live). Run it in a www.bahn.de tab that has fully loaded. Content-Type is required (415 without). Leg time fields: the web API uses abfahrtsZeitpunkt/ankunftsZeitpunkt (+ ez* for real time) per db-vendo-client's dbweb parser; the spike recorded abfahrt.sollzeit, so both are read. Discount cards (BahnCard) and children are not mapped yet.","recorded_at":"2026-11-07T11:20:00+01:00","recorded_by":"C4"},"requires_login":false,"schema":"https://wield.run/schema/recipe/v1.json","site":{"country":"DE","id":"bahn.de","language":"de","login_url":"https://www.bahn.de/buchung/login","name":"Deutsche Bahn","origin":"https://www.bahn.de","origins":["https://www.bahn.de"]},"steps":[{"description":"Free text to HAFAS station id (type ST = station).","expect":{"assert":"length(body[?type=='ST']) > `0`","content_type":"json","status":[200]},"extract":{"json":{"eva":"[?type=='ST'] | [0].extId","id":"[?type=='ST'] | [0].id","name":"[?type=='ST'] | [0].name"}},"id":"from_station","request":{"headers":{"Accept":"application/json","Accept-Language":"de"},"method":"GET","query":{"limit":"10","suchbegriff":"{{params.from}}","typ":"ALL"},"url":"https://www.bahn.de/web/api/reiseloesung/orte"}},{"expect":{"assert":"length(body[?type=='ST']) > `0`","content_type":"json","status":[200]},"extract":{"json":{"eva":"[?type=='ST'] | [0].extId","id":"[?type=='ST'] | [0].id","name":"[?type=='ST'] | [0].name"}},"id":"to_station","request":{"headers":{"Accept":"application/json","Accept-Language":"de"},"method":"GET","query":{"limit":"10","suchbegriff":"{{params.to}}","typ":"ALL"},"url":"https://www.bahn.de/web/api/reiseloesung/orte"}},{"delay_ms":300,"description":"Connection search with prices. Answers 201 on success. Minimal body from spikes/bahn.md; one adult, no discount card.","expect":{"assert":"body.verbindungen != null","content_type":"json","status":[200,201]},"extract":{"json":{"connections":"verbindungen[].{departure: verbindungsAbschnitte[0].abfahrtsZeitpunkt || verbindungsAbschnitte[0].abfahrt.sollzeit, departure_realtime: verbindungsAbschnitte[0].ezAbfahrtsZeitpunkt || verbindungsAbschnitte[0].abfahrt.echtzeit || `null`, arrival: verbindungsAbschnitte[-1].ankunftsZeitpunkt || verbindungsAbschnitte[-1].ankunft.sollzeit, arrival_realtime: verbindungsAbschnitte[-1].ezAnkunftsZeitpunkt || verbindungsAbschnitte[-1].ankunft.echtzeit || `null`, from: verbindungsAbschnitte[0].abfahrtsOrt, to: verbindungsAbschnitte[-1].ankunftsOrt, duration_min: verbindungsDauerInSeconds && floor(verbindungsDauerInSeconds / `60`) || `null`, transfers: umstiegsAnzahl, trains: verbindungsAbschnitte[?verkehrsmittel.typ=='PUBLICTRANSPORT'].verkehrsmittel.mittelText, price_eur: angebotsPreis.betrag || `null`, currency: angebotsPreis.waehrung || `null`, price_class: angebotsPreisKlasse || `null`, legs: verbindungsAbschnitte[?verkehrsmittel.typ=='PUBLICTRANSPORT'].{train: verkehrsmittel.mittelText || verkehrsmittel.name, category: verkehrsmittel.produktGattung, direction: verkehrsmittel.richtung || `null`, from: abfahrtsOrt, to: ankunftsOrt, departure: abfahrtsZeitpunkt || abfahrt.sollzeit, arrival: ankunftsZeitpunkt || ankunft.sollzeit, departure_platform: halte[0].ezGleis || halte[0].gleis || `null`, arrival_platform: halte[-1].ezGleis || halte[-1].gleis || `null`}}","later_ref":"verbindungReference.later"}},"id":"search","request":{"body":{"type":"json","value":{"abfahrtsHalt":"{{steps.from_station.id}}","anfrageZeitpunkt":"{{params.date}}T{{params.time}}:00","ankunftSuche":"{{params.mode}}","ankunftsHalt":"{{steps.to_station.id}}","deutschlandTicketVorhanden":false,"klasse":"{{params.travel_class}}","nurDeutschlandTicketVerbindungen":false,"pagingReference":"{{params.page_ref}}","produktgattungen":["ICE","EC_IC","IR","REGIONAL","SBAHN","BUS","SCHIFF","UBAHN","TRAM","ANRUFPFLICHTIG"],"reisende":[{"alter":[],"anzahl":"{{params.adults}}","ermaessigungen":[{"art":"KEINE_ERMAESSIGUNG","klasse":"KLASSENLOS"}],"typ":"ERWACHSENER"}],"schnelleVerbindungen":true}},"headers":{"Accept":"application/json","Accept-Language":"de","Content-Type":"application/json; charset=utf-8"},"method":"POST","url":"https://www.bahn.de/web/api/angebote/fahrplan"}}],"task":"Search train connections between two stations with prices","tos":{"notes":"bahn.de's terms do not allow automated bulk queries of timetable or fare data. This recipe performs one user-initiated search at a time from the user's own browser and session, at human pace (3 requests). Do not poll it or page through results in bulk. It never books: booking and payment stay with the user on bahn.de.","reviewed":false},"verify":{"checks":["length(output.connections) > `0`","output.from == 'Berlin Hbf'","output.to == 'München Hbf'","starts_with(output.connections[0].departure, '2026-11-20')","length(output.connections[?price_eur != `null`]) > `0`","output.connections[0].duration_min > `200`"],"example_params":{"date":"2026-11-20","from":"Berlin Hbf","time":"08:00","to":"München Hbf"},"max_ms":8000},"version":1}