Authenticatie & modi
Elk verzoek heeft je sleutel nodig in de header Authorization: Bearer …. We geven sleutels uit na een kort gesprek – zelf registreren is niet mogelijk.
https://api.listnride.com/v1Echte fietsen en prijzen, gesimuleerde boekingen: de link opent een testpagina, niemand betaalt en de verhuurder krijgt geen bericht.
Echte boekingen via de ListNRide-checkout.
curl "https://api.listnride.com/v1/rides?lat=52.52&lng=13.40" \
-H "Authorization: Bearer lnr_test_…"Zo werkt een boeking
Je hebt geen eigen checkout nodig: de klant boekt en betaalt bij ons en komt daarna terug op je website.
Fietsen vinden
GET /v1/ridesop plaats, periode en categorie.Checkout-sessie aanmaken
POST /v1/checkout/sessions– je krijgt de prijs en een link.Klant doorsturen
Boeken en betalen in de ListNRide-checkout, daarna terug naar jou.
Status ontvangen
Via webhook of met
GET /v1/bookings/{id}.
Testmodus stap voor stap
Met een testsleutel werkt alles zoals live – alleen betaalt niemand en merkt geen verhuurder iets. Test zo de hele route één keer voordat je live gaat.
Sessie aanmaken
POST /v1/checkout/sessionsmetlnr_test_…. Prijzen en beschikbaarheid zijn echt.Link openen
De
urlopent een testpagina in plaats van de checkout. Kies daar „Complete test booking”.Terugkeer controleren
De klant komt terug op je
return_urlmetbooking=bkg_test_…enstatus=success.Webhook controleren
Is er een webhook-URL ingesteld, dan komt
booking.confirmedmet"mode": "test"binnen een minuut binnen.
Endpoints
Fietsen in de buurt van een plaats of van één verhuurder. Met een periode toont availability.units_available de vrije exemplaren.
| Parameter | Omschrijving |
|---|---|
| lat, lng | Middelpunt van de zoekopdracht (of lister) |
| radius_km | 0,1–100, standaard 15 |
| bbox | Kaartuitsnede minLng,minLat,maxLng,maxLat in plaats van lat/lng |
| from, to | Periode, ISO-datum of -tijdstip |
| quantity | Aantal gelijke fietsen, standaard 1 |
| category | bijv. e-bike,cargo-bike |
| price_min price_max | Prijs per dag in centen, incl. servicekosten en basisverzekering |
| rider_height | Lengte van de fietser in cm (150–210) – vindt fietsen in de juiste maat en unisize |
| frame_size brand | Exacte framemaat of merk, bijv. M of Gazelle |
| accessories | Meegeleverde uitrusting, alles moet aanwezig zijn: helmet,lock,lights,basket,childseat,trailer,gps,repair_kit |
| instant_booking top_booked | true: alleen directe bevestiging / alleen populairste fietsen |
| min_rating lister_type type | Minimale beoordeling, business of private, bike of accessory |
| sort | recommended · distance · price_asc · price_desc · rating · popular |
| limit, cursor | Paginering, maximaal 100 per pagina |
{
"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"
}Eén fiets met beschrijving, alle foto’s, uitrusting, borg en verzekering.
Plus alles wat een productpagina nodig heeft: totaalprijzen voor 1–28 dagen, lengte van de fietser, boekingsregels, openingstijden, annuleringsvoorwaarden en boekbare extra’s met bezorgzones.
{
"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" }]
}Vrije exemplaren per dag plus ophaal- en inlevervensters in lokale tijd, tot 92 dagen per verzoek. Sluitingsdagen en openingstijden zijn al verwerkt – ideaal voor je eigen datumkiezer. De bindende controle doen POST /v1/quotes en de checkout.
{
"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"]
}, …]
}Geverifieerde beoordelingen van een fiets, nieuwste eerst, met gemiddelde en totaal. Auteurs verschijnen met voornaam en initiaal. Alle beoordelingen van een verhuurder: GET /v1/listers/{id}/reviews.
Openbaar profiel van een verhuurder: naam, locatie, beoordeling, afgeronde boekingen, aantal fietsen, directe bevestiging, boekingsregels, openingstijden en bezorgzones. Particuliere verhuurders verschijnen met voornaam en zonder straat.
De annuleringsvoorwaarden die voor elke boeking gelden: vanaf 72 uur voor het ophalen wordt alles terugbetaald, daaronder een deel van de huur per tijdvenster. Annuleert de verhuurder, dan krijgt de klant alles terug.
Alle categorieën met Duitse en Engelse naam. Een hoofdcategorie zoals e-bike omvat bij het zoeken ook de subcategorieën.
Alle plaatsen met boekbare fietsen, die met de meeste fietsen eerst. Met q zoek je in alle talen (bijv. q=munchen), met country filter je op land en locale kiest de taal van de namen. Eén plaats: GET /v1/places/{id}.
In plaats van één bepaalde fiets boekt je klant een klasse – bijv. ‘E-bike, middenklasse’ in Berlijn – en ListNRide zoekt een passende verhuurder. Opvragen met place of lat/lng. Boeken gaat via een checkout-sessie met class en size (lengte van de fietser).
{
"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
}Berekent de exacte prijs zoals de ListNRide-checkout: huur, korting, servicekosten, basisverzekering, extra’s (insurance_plus) en bezorging op een adres – zonder iets te reserveren. Een offerte omvat fietsen van één verhuurder of één 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 }Maakt een checkout-sessie aan. De ListNRide-checkout controleert prijs en beschikbaarheid. De link is 24 uur geldig; aantal en tijden staan in de checkout al ingevuld.
| Veld | Omschrijving |
|---|---|
| ride * | Fiets-ID ride_… |
| class, size | In plaats van ride: een klasse uit GET /v1/classes en de lengte van de fietser (165-175 … of Unisize) |
| from, to * | Ophaal- en inleverdag, YYYY-MM-DD |
| pickup_time, return_time | HH:MM, standaard 10:00 / 17:00 |
| quantity | Aantal, 1–50, standaard 1 |
| return_url * | Waar de klant na het boeken terugkomt (https), met checkout_session, booking en status=success |
| cancel_url | Optioneel, bij annuleren (https) |
| locale | de · en · fr · es · it · nl |
| client_reference | Je eigen referentie |
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://jouw-site.nl/bedankt",
"locale": "nl"
}'
# → { "id": "cs_O8t1…", "amount_total": 7800,
# "url": "https://www.listnride.nl/api/go/p/BHTm…" }Status van de sessie: open, booked (met booking-ID) of expired.
| status | Omschrijving |
|---|---|
| awaiting_payment | Klant zit in de checkout, nog niet betaald |
| requested | Betaald of gereserveerd, wacht op akkoord van de verhuurder |
| accepted | Verhuurder akkoord, betaling loopt |
| confirmed | Bevestigd |
| completed | Huur afgerond |
| canceled_by_lister · canceled_by_customer · canceled | Geannuleerd |
| expired | Niet betaald of niet op tijd geaccepteerd |
Alle boekingen uit je checkout-sessies, nieuwste eerst. Filter op status of je client_reference. Een testsleutel toont testboekingen, een live-sleutel echte boekingen. Geannuleerde boekingen bevatten cancellation met terugbetalingsbedrag en -status.
Annuleert een boeking namens je klant – volgens dezelfde regels als op listnride.com: vanaf 72 uur voor het ophalen wordt alles terugbetaald, daaronder een deel van de huur. De verhuurder krijgt bericht, jij ontvangt booking.canceled_by_customer en de terugbetaling gaat naar het betaalmiddel van de klant.
Controleer eerst met GET /v1/bookings/{id}/cancellation – laat zien of annuleren kan en de exacte terugbetaling, zonder iets te wijzigen. Annuleren vereist de scope bookings:cancel, die we op verzoek activeren. Optioneel: reason (changed_mind, found_better, timing_issue, price_too_high, personal_reasons, other) en comment.
# 1. Voorbeeld: kan het geannuleerd worden en wat krijgt de klant terug?
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. Annuleren
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"Zet ?aff=JOUWCODE achter elke ListNRide-link – elke pagina, elke taal. Boekt de klant binnen de afgesproken termijn, dan telt de boeking voor jou; de laatste klik wint. Boekingen via je checkout-sessies tellen altijd voor jou, ook zonder klik.
De provisie wordt individueel afgesproken en is gebaseerd op de kosten die ListNRide aan de boeking verdient. Ze telt zodra de huur is afgelopen; annuleert de verhuurder, dan is er geen provisie. GET /v1/commissions toont klikken, boekingen, staffel en provisie per maand – zonder klantgegevens. Er wordt maandelijks afgerekend via creditnota.
# Partnerlink – werkt op elke pagina
https://www.listnride.de/berlin/e-bike?aff=NEEDABIKE
# Je provisie voor een maand
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"Webhooks
Verandert de status van een boeking, dan sturen we een POST naar je webhook-URL, bijv. booking.confirmed. Antwoord met 2xx – anders proberen we het opnieuw na 1 min, 5 min, 30 min en tot 24 uur. Met ping test je de verbinding; de id van het event blijft bij herhalingen gelijk.
Controleer elk bericht met de header LNR-Signature: t=…,v1=…: HMAC-SHA256 over t + "." + body met je geheim whsec_…. Gebruik de onbewerkte body en weiger berichten waarvan t ouder is dan 5 minuten.
POST https://jouw-site.nl/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: de onbewerkte body, precies zoals ontvangen
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: de onbewerkte body, precies zoals ontvangen
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", ""))Fouten & limieten
Fouten hebben altijd dezelfde vorm. Met de request_id vinden we je geval snel terug.
Limieten per sleutel: een limiet per minuut en een dagquotum (headers X-Quota-Limit, X-Quota-Remaining). Een zoekopdracht kun je hooguit 500 resultaten diep doorbladeren – beperk hem met plaats, straal, categorie of periode. Massaal ophalen en doorverkopen van de gegevens is niet toegestaan.
Veilig opnieuw proberen: stuur de header Idempotency-Key mee bij POST /v1/checkout/sessions en POST /v1/bookings/{id}/cancel. Een herhaling met dezelfde sleutel en dezelfde inhoud geeft het eerste antwoord terug (header Idempotent-Replayed: true) in plaats van twee keer te handelen. Sleutels blijven 24 uur bewaard.
| 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" } }SDK’s & tools
Officiële clients als één bestand zonder afhankelijkheden – kopieer ze in je project. Ze regelen authenticatie, pagineren, opnieuw proberen bij 429/5xx, Idempotency-Keys en het controleren van webhooks.
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" }); // de Idempotency-Key wordt automatisch toegevoegdVersies
De versie staat in het pad. Binnen /v1 komen er alleen velden bij – niets wordt verwijderd of hernoemd. Grote wijzigingen verschijnen als /v2, en /v1 blijft minstens 12 maanden werken. De machineleesbare beschrijving (OpenAPI 3.1) staat op /openapi.json en https://api.listnride.com/v1/openapi.json.
Wijzigingen
Idempotency-Key voor schrijvende aanroepen, Postman-collectie, officiële clients voor Node.js, PHP en Python.
Affiliate: partnerlinks met
?aff=CODEenGET /v1/commissions.GET /v1/bookings, annuleringsvoorbeeld enPOST /v1/bookings/{id}/cancel(scopebookings:cancel).Zoekfilters (prijs, lengte, uitrusting, kaartuitsnede …), prijsstaffels, openingstijden, annuleringsvoorwaarden, beschikbaarheidskalender, beoordelingen en verhuurdersprofielen.
Plaatsen, voertuigklassen,
POST /v1/quotes, boeken per klasse en een dagquotum per sleutel.Start van v1: fietsen, categorieën, checkout-sessies, boekingen, webhooks en testmodus.
Toegang aanvragen
Vertel ons over je website en wat je van plan bent. Je krijgt eerst een testsleutel – live gaan volgt na een kort gesprek.
partner@listnride.com