Anmeldung & Modi
Jede Anfrage braucht deinen Schlüssel im Kopf Authorization: Bearer …. Schlüssel vergeben wir nach einem kurzen Gespräch – es gibt keine Selbstregistrierung.
https://api.listnride.com/v1Echte Räder und Preise, Buchungen nur simuliert: Der Link führt auf eine Testseite, es gibt keine Zahlung und keine Nachricht an den Vermieter.
Echte Buchungen über die ListNRide-Kasse.
curl "https://api.listnride.com/v1/rides?lat=52.52&lng=13.40" \
-H "Authorization: Bearer lnr_test_…"Ablauf einer Buchung
Du brauchst keine eigene Kasse: Der Kunde bucht und bezahlt bei uns und landet danach wieder auf deiner Seite.
Räder finden
GET /v1/ridesnach Ort, Zeitraum und Kategorie.Kassensitzung anlegen
POST /v1/checkout/sessions– du bekommst Preis und Link.Kunden weiterleiten
Buchen und Bezahlen in der ListNRide-Kasse, dann zurück zu dir.
Status erhalten
Per Benachrichtigung oder
GET /v1/bookings/{id}.
Testmodus Schritt für Schritt
Mit einem Testschlüssel läuft alles wie live – nur bezahlt niemand, und kein Vermieter bekommt etwas mit. So baust du die ganze Strecke einmal durch, bevor du live gehst.
Sitzung anlegen
POST /v1/checkout/sessionsmitlnr_test_…. Preis und Verfügbarkeit sind echt.Link öffnen
Die
urlführt auf eine Testseite statt in die Kasse. Dort „Testbuchung abschließen“ wählen.Rücksprung prüfen
Der Kunde landet auf deiner
return_urlmitbooking=bkg_test_…undstatus=success.Benachrichtigung prüfen
Mit hinterlegter Adresse kommt innerhalb einer Minute
booking.confirmedmit"mode": "test".
Endpunkte
Räder in der Nähe eines Ortes oder eines Vermieters. Mit Zeitraum zeigt availability.units_available die freien Einheiten.
| Parameter | Bedeutung |
|---|---|
| lat, lng | Mittelpunkt der Suche (oder lister) |
| radius_km | 0,1–100, Standard 15 |
| bbox | Kartenausschnitt minLng,minLat,maxLng,maxLat statt lat/lng |
| from, to | Zeitraum, ISO-Datum oder -Zeitpunkt |
| quantity | Anzahl gleicher Räder, Standard 1 |
| category | z. B. e-bike,cargo-bike |
| price_min price_max | Preis pro Tag in Cent, inkl. Servicegebühr und Basisversicherung |
| rider_height | Körpergröße in cm (150–210) – findet Räder in passender Größe und Unisize |
| frame_size brand | Exakte Rahmengröße bzw. Marke, z. B. M oder Gazelle |
| accessories | Mitgeliefertes Zubehör, alles muss dabei sein: helmet,lock,lights,basket,childseat,trailer,gps,repair_kit |
| instant_booking top_booked | true: nur Sofortbestätigung / nur Top gebuchte Räder |
| min_rating lister_type type | Mindestbewertung, business oder private, bike oder accessory |
| sort | recommended · distance · price_asc · price_desc · rating · popular |
| limit, cursor | Blättern, höchstens 100 je Seite |
{
"object": "list",
"data": [{
"id": "ride_oEbNgLPApUJf52PkgHU49A",
"name": "KRZBERG – Single Speed",
"category": { "id": "single-speed" },
"price": { "currency": "EUR", "per_day": 2500 },
"lister": { "id": "lis_VTknvPc20LBQbXE9p7dt6A" },
"instant_booking": true,
"distance_km": 1.46
}],
"has_more": true, "next_cursor": "eyJvIjoyMH0"
}Ein Rad mit Beschreibung, allen Bildern, Ausstattung, Kaution und Versicherung.
Dazu alles, was eine Produktseite braucht: Gesamtpreise für 1–28 Tage, Körpergröße, Buchungsregeln, Öffnungszeiten, Stornoregeln und buchbare Extras mit Lieferzonen.
{
"price": { "per_day": 2500, "tiers": [
{ "days": 1, "total": 2500 },
{ "days": 7, "total": 15599, "discount": 1400 } ] },
"size": { "rider_height": { "range": "175-185" } },
"booking_rules": { "min_days": 1, "time_slot_minutes": 30 },
"opening_hours": { "monday": ["09:00-18:00"], … },
"cancellation_policy": { "by_customer": [
{ "hours_before_pickup_min": 72, "refund_percent_of_rental": 100 }, … ] },
"extras": [{ "code": "insurance_plus" }, { "code": "delivery" }]
}Freie Exemplare je Tag plus Abhol- und Rückgabefenster in Ortszeit, bis zu 92 Tage pro Abruf. Ruhetage und Öffnungszeiten sind schon eingerechnet – ideal für deinen eigenen Datumswähler. Verbindlich prüfen POST /v1/quotes und die Kasse.
{
"object": "availability",
"units_total": 4,
"days": [{
"date": "2026-11-17",
"units_available": 3,
"closed": false,
"pickup_windows": ["09:00-18:00"],
"return_windows": ["09:00-18:00"]
}, …]
}Verifizierte Bewertungen eines Rads, neueste zuerst, mit Durchschnitt und Gesamtzahl. Verfasser erscheinen mit Vorname und Initial. Alle Bewertungen eines Vermieters: GET /v1/listers/{id}/reviews.
Öffentliches Profil eines Vermieters: Name, Standort, Bewertung, abgeschlossene Buchungen, Anzahl Räder, Sofortbestätigung, Buchungsregeln, Öffnungszeiten und Lieferzonen. Privatvermieter erscheinen mit Vorname und ohne Straße.
Die Stornoregeln, die für jede Buchung gelten: ab 72 Stunden vor Abholung wird alles erstattet, darunter ein Anteil der Miete je Zeitfenster. Storniert der Vermieter, bekommt der Kunde alles zurück.
Alle Kategorien mit deutschem und englischem Namen. Eine Oberkategorie wie e-bike schließt bei der Suche ihre Unterkategorien ein.
Alle Orte mit buchbaren Rädern, die mit den meisten Rädern zuerst. Mit q suchst du in allen Sprachen (z. B. q=münch), mit country filterst du nach Land, locale wählt die Sprache der Namen. Einzelner Ort: GET /v1/places/{id}.
Statt eines bestimmten Rads bucht dein Kunde eine Klasse – z. B. „E-Bike, Mittelklasse“ in Berlin – und ListNRide findet einen passenden Verleiher. Abfrage mit place oder lat/lng. Gebucht wird über eine Kassensitzung mit class und size (Fahrergröße).
{
"id": "berlin.e-bike.mid",
"object": "class",
"category": { "id": "e-bike" },
"tier": { "id": "mid" },
"price": { "currency": "EUR", "per_day": 3900 },
"sizes": ["150-165", "165-175", "175-185", "185-205", "Unisize"],
"listers_nearby": 12
}Berechnet den genauen Preis wie die ListNRide-Kasse: Miete, Rabatt, Servicegebühr, Basisversicherung, Extras (insurance_plus) und Lieferung an eine Adresse – ohne etwas zu reservieren. Ein Angebot umfasst Räder eines Vermieters oder eine Klasse.
curl -X POST https://api.listnride.com/v1/quotes \
-H "Authorization: Bearer lnr_test_…" \
-H "Content-Type: application/json" \
-d '{
"from": "2026-11-17", "to": "2026-11-19",
"items": [{ "ride": "ride_jK6n…", "quantity": 2,
"extras": ["insurance_plus"] }],
"delivery_address": "Torstraße 1, 10119 Berlin"
}'
# → "amounts": { "rental": 6000, "service_fee": 1100,
# "insurance_plus": 900, "delivery": 1500, "total": 9600 }Legt eine Kassensitzung an. Preis und Verfügbarkeit prüft dabei die ListNRide-Kasse. Der Link ist 24 Stunden gültig; Anzahl und Uhrzeiten sind in der Kasse vorausgewählt.
| Feld | Bedeutung |
|---|---|
| ride * | Rad-ID ride_… |
| class, size | Statt ride: Klasse aus GET /v1/classes und Fahrergröße (165-175 … oder Unisize) |
| from, to * | Abhol- und Rückgabetag, YYYY-MM-DD |
| pickup_time, return_time | HH:MM, Standard 10:00 / 17:00 |
| quantity | Anzahl, 1–50, Standard 1 |
| return_url * | Hierhin kommt der Kunde nach der Buchung zurück (https), mit checkout_session, booking und status=success |
| cancel_url | Optional, für den Abbruch (https) |
| locale | de · en · fr · es · it · nl |
| client_reference | Deine eigene Nummer |
curl -X POST https://api.listnride.com/v1/checkout/sessions \
-H "Authorization: Bearer lnr_test_…" \
-H "Content-Type: application/json" \
-d '{
"ride": "ride_jK6nvpDczET3Adx8AKKn1w",
"from": "2026-11-17", "to": "2026-11-18",
"pickup_time": "09:00", "return_time": "17:00",
"return_url": "https://deine-seite.de/danke",
"locale": "de"
}'
# → { "id": "cs_O8t1…", "amount_total": 7800,
# "url": "https://www.listnride.de/api/go/p/BHTm…" }Status der Sitzung: open, booked (mit booking-ID) oder expired.
| status | Bedeutung |
|---|---|
| awaiting_payment | Kunde ist in der Kasse, noch nicht bezahlt |
| requested | Bezahlt bzw. vorgemerkt, Vermieter muss zusagen |
| accepted | Vermieter hat zugesagt, Zahlung läuft |
| confirmed | Fest gebucht |
| completed | Miete abgeschlossen |
| canceled_by_lister · canceled_by_customer · canceled | Storniert |
| expired | Nicht bezahlt oder nicht rechtzeitig angenommen |
Alle Buchungen aus deinen Kassensitzungen, neueste zuerst. Filter nach status oder deiner client_reference. Ein Testschlüssel listet Testbuchungen, ein Live-Schlüssel echte Buchungen. Stornierte Buchungen tragen cancellation mit Erstattungsbetrag und -status.
Storniert eine Buchung im Namen deines Kunden – nach denselben Regeln wie auf listnride.com: ab 72 Stunden vor Abholung wird alles erstattet, darunter ein Anteil der Miete. Der Vermieter wird benachrichtigt, du bekommst booking.canceled_by_customer, und die Erstattung geht auf das Zahlungsmittel des Kunden zurück.
Vorher prüfen mit GET /v1/bookings/{id}/cancellation – zeigt, ob ein Storno möglich ist, und die genaue Erstattung, ohne etwas zu ändern. Stornieren braucht den Scope bookings:cancel, den wir auf Wunsch freischalten. Optional: reason (changed_mind, found_better, timing_issue, price_too_high, personal_reasons, other) und comment.
# 1. Vorschau: geht ein Storno, und was bekommt der Kunde zurück?
curl https://api.listnride.com/v1/bookings/bkg_gr9z…/cancellation \
-H "Authorization: Bearer lnr_live_…"
# → "cancelable": true, "refund": { "amount": 7300 },
# "breakdown": { "rental_refunded_percent": 75 }
# 2. Stornieren
curl -X POST https://api.listnride.com/v1/bookings/bkg_gr9z…/cancel \
-H "Authorization: Bearer lnr_live_…" \
-H "Content-Type: application/json" \
-d '{ "reason": "timing_issue" }'
# → "status": "canceled_by_customer"Häng ?aff=DEINCODE an jeden ListNRide-Link – jede Seite, jede Sprache. Bucht der Kunde innerhalb der vereinbarten Frist, zählt die Buchung für dich; der letzte Klick gewinnt. Buchungen über deine Kassensitzungen zählen immer für dich, auch ohne Klick.
Die Provision wird individuell vereinbart und richtet sich nach den Gebühren, die ListNRide an der Buchung verdient. Sie zählt, sobald die Miete beendet ist; storniert der Vermieter, gibt es keine. GET /v1/commissions zeigt Klicks, Buchungen, Stufe und Provision je Monat – ohne Kundendaten. Abgerechnet wird monatlich per Gutschrift.
# Partner-Link – funktioniert auf jeder Seite
https://www.listnride.de/berlin/e-bike?aff=NEEDABIKE
# Deine Provision für einen Monat
curl "https://api.listnride.com/v1/commissions?month=2026-09" \
-H "Authorization: Bearer lnr_live_…"
# → "clicks": 4812, "bookings": 91, "tier": "Stufe 3 · 30 %",
# "commission_net": { "amount": 54120 }, "status": "approved"Benachrichtigungen
Ändert sich der Status einer Buchung, schicken wir ein POST an deine hinterlegte Adresse, z. B. booking.confirmed. Antworte mit 2xx – sonst versuchen wir es nach 1 Min., 5 Min., 30 Min. und bis zu 24 Std. erneut. Mit ping kannst du die Verbindung testen; die Ereignis-id bleibt bei Wiederholungen gleich.
Prüfe jede Nachricht mit der Kopfzeile LNR-Signature: t=…,v1=…: HMAC-SHA256 über t + "." + body mit deinem Geheimnis whsec_…. Rechne mit dem unveränderten Body und weise Nachrichten ab, deren t älter als 5 Minuten ist.
POST https://deine-seite.de/hooks/listnride
LNR-Event: booking.confirmed
LNR-Signature: t=1791210000,v1=5f2c…
{
"id": "evt_Qm3xT0bWl2kZ8yQe",
"object": "event",
"type": "booking.confirmed",
"created": "2026-11-02T09:14:03.000Z",
"data": { "object": {
"id": "bkg_gr9z-CSUh4I8UrC9WEwW2Q",
"object": "booking",
"mode": "live",
"status": "confirmed",
"reference": "LNR-w4kKb",
"checkout_session": "cs_O8t1fc2rdEG2GyYTqghvfA",
"ride": "ride_jK6nvpDczET3Adx8AKKn1w",
"from": "2026-11-17T08:00:00.000Z",
"to": "2026-11-18T16:00:00.000Z",
"quantity": 1,
"amount_total": 7800,
"currency": "EUR",
"client_reference": "NB-1042"
} }
}const crypto = require("crypto");
// rawBody: der unveränderte Body, wie er ankam
function verify(rawBody, header, secret) {
const p = Object.fromEntries(header.split(",").map(x => x.split("=")));
if (Math.abs(Date.now() / 1000 - Number(p.t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret)
.update(`${p.t}.${rawBody}`).digest("hex");
return typeof p.v1 === "string" && p.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(p.v1));
}
function lnr_verify(string $rawBody, string $header, string $secret): bool {
$p = [];
foreach (explode(",", $header) as $part) {
[$k, $v] = array_pad(explode("=", $part, 2), 2, "");
$p[$k] = $v;
}
if (abs(time() - (int)($p["t"] ?? 0)) > 300) return false;
$expected = hash_hmac("sha256", $p["t"] . "." . $rawBody, $secret);
return hash_equals($expected, $p["v1"] ?? "");
}
// $raw = file_get_contents("php://input");
// lnr_verify($raw, $_SERVER["HTTP_LNR_SIGNATURE"] ?? "", "whsec_…");
import hashlib, hmac, time
# raw_body: der unveränderte Body, wie er ankam
def verify(raw_body: bytes, header: str, secret: str) -> bool:
p = dict(x.split("=", 1) for x in header.split(",") if "=" in x)
if abs(time.time() - int(p.get("t", 0))) > 300:
return False
expected = hmac.new(secret.encode(), p["t"].encode() + b"." + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, p.get("v1", ""))Fehler & Limits
Fehler haben immer dieselbe Form. Mit der request_id finden wir deinen Fall schnell.
Grenzen pro Schlüssel: ein Minutenlimit und ein Tageskontingent (Kopfzeilen X-Quota-Limit, X-Quota-Remaining). Eine Suche lässt sich höchstens 500 Treffer tief durchblättern – grenze sie mit Ort, Radius, Kategorie oder Zeitraum ein. Massenabruf und Weiterverkauf der Daten sind nicht erlaubt.
Sicher wiederholen: Schick bei POST /v1/checkout/sessions und POST /v1/bookings/{id}/cancel den Kopf Idempotency-Key mit. Eine Wiederholung mit gleichem Schlüssel und gleichem Inhalt liefert die erste Antwort (Kopf Idempotent-Replayed: true), statt doppelt zu handeln. Schlüssel gelten 24 Stunden.
| HTTP | code |
|---|---|
| 400 | parameter_missing, parameter_invalid, outside_opening_hours, duration_too_short, duration_too_long, multiple_listers, delivery_unavailable, pagination_limit |
| 401 | missing_api_key, invalid_api_key |
| 403 | missing_scope |
| 404 | resource_missing, route_not_found |
| 409 | ride_unavailable, already_canceled, processing, already_started |
| 429 | rate_limited, daily_quota_exceeded, too_many_failed_attempts – X-RateLimit-*, X-Quota-*, Retry-After |
{ "error": {
"type": "invalid_request_error",
"code": "ride_unavailable",
"message": "The ride is not available for this period and quantity.",
"param": "ride",
"request_id": "req_UqrIw8P5wzwT" } }SDKs & Werkzeuge
Offizielle Clients als einzelne Datei ohne Abhängigkeiten – einfach ins Projekt kopieren. Sie übernehmen Anmeldung, Blättern, Wiederholung bei 429/5xx, Idempotency-Keys und die Prüfung von Benachrichtigungen.
const { ListNRide } = require("./listnride");
const lnr = new ListNRide({ apiKey: process.env.LNR_API_KEY });
for await (const ride of lnr.rides.all({ lat: 52.52, lng: 13.40, category: "e-bike" })) {
console.log(ride.name, ride.price.per_day);
}
const session = await lnr.checkoutSessions.create({ ride: "ride_…", from: "2026-11-17",
to: "2026-11-19", return_url: "https://your-site.com/thanks" }); // Idempotency-Key wird automatisch gesetztVersionen
Die Version steht im Pfad. Innerhalb von /v1 kommen nur Felder dazu – nichts wird entfernt oder umbenannt. Größere Änderungen erscheinen als /v2, und /v1 läuft mindestens 12 Monate weiter. Die maschinenlesbare Beschreibung (OpenAPI 3.1) liegt unter /openapi.json bzw. https://api.listnride.com/v1/openapi.json.
Änderungen
Idempotency-Key für schreibende Aufrufe, Postman-Sammlung, offizielle Clients für Node.js, PHP und Python.
Affiliate: Partner-Links mit
?aff=CODEundGET /v1/commissions.GET /v1/bookings, Storno-Vorschau undPOST /v1/bookings/{id}/cancel(Scopebookings:cancel).Suchfilter (Preis, Körpergröße, Zubehör, Kartenausschnitt …), Preisstaffel, Öffnungszeiten, Stornoregeln, Verfügbarkeitskalender, Bewertungen und Vermieterprofile.
Orte, Fahrzeugklassen,
POST /v1/quotes, Buchung nach Klasse und ein Tageskontingent je Schlüssel.Start von v1: Räder, Kategorien, Kassensitzungen, Buchungen, Benachrichtigungen und Testmodus.
Zugang anfragen
Schreib uns mit deiner Website und was du vorhast. Du bekommst zuerst einen Testschlüssel – live geht es nach einem kurzen Gespräch.
partner@listnride.com