Authentification & modes
Chaque requête nécessite votre clé dans l’en-tête Authorization: Bearer …. Nous attribuons les clés après un court échange – il n’y a pas d’inscription libre.
https://api.listnride.com/v1Vrais vélos et vrais prix, réservations simulées : le lien ouvre une page de test, personne ne paie et le loueur n’est pas prévenu.
De vraies réservations via le paiement ListNRide.
curl "https://api.listnride.com/v1/rides?lat=52.52&lng=13.40" \
-H "Authorization: Bearer lnr_test_…"Déroulement d’une réservation
Pas besoin de votre propre tunnel de paiement : le client réserve et paie chez nous, puis revient sur votre site.
Trouver des vélos
GET /v1/ridespar lieu, période et catégorie.Créer une session de paiement
POST /v1/checkout/sessions– vous obtenez le prix et un lien.Rediriger le client
Réservation et paiement chez ListNRide, puis retour chez vous.
Recevoir le statut
Par webhook ou via
GET /v1/bookings/{id}.
Le mode test pas à pas
Avec une clé de test, tout fonctionne comme en production – sauf que personne ne paie et qu’aucun loueur n’est impliqué. Testez tout le parcours une fois avant la mise en ligne.
Créer une session
POST /v1/checkout/sessionsaveclnr_test_…. Prix et disponibilités sont réels.Ouvrir le lien
L’
urlouvre une page de test au lieu du paiement. Choisissez « Complete test booking ».Vérifier le retour
Le client arrive sur votre
return_urlavecbooking=bkg_test_…etstatus=success.Vérifier le webhook
Si une URL de webhook est configurée,
booking.confirmedavec"mode": "test"arrive en moins d’une minute.
Endpoints
Vélos autour d’un lieu ou d’un loueur. Avec une période, availability.units_available indique les unités libres.
| Paramètre | Description |
|---|---|
| lat, lng | Centre de la recherche (ou lister) |
| radius_km | 0,1–100, par défaut 15 |
| bbox | Zone de carte minLng,minLat,maxLng,maxLat au lieu de lat/lng |
| from, to | Période, date ou date-heure ISO |
| quantity | Nombre de vélos identiques, par défaut 1 |
| category | p. ex. e-bike,cargo-bike |
| price_min price_max | Prix par jour en centimes, frais de service et assurance de base inclus |
| rider_height | Taille du cycliste en cm (150–210) – trouve les vélos de la bonne taille et les unisize |
| frame_size brand | Taille de cadre ou marque exacte, p. ex. M ou Gazelle |
| accessories | Équipement fourni, tout doit être présent : helmet,lock,lights,basket,childseat,trailer,gps,repair_kit |
| instant_booking top_booked | true : uniquement confirmation immédiate / uniquement vélos les plus réservés |
| min_rating lister_type type | Note minimale, business ou private, bike ou accessory |
| sort | recommended · distance · price_asc · price_desc · rating · popular |
| limit, cursor | Pagination, 100 au maximum par page |
{
"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"
}Un vélo avec description, toutes les photos, équipement, caution et assurance.
Avec tout ce dont une page produit a besoin : prix totaux de 1 à 28 jours, taille du cycliste, règles de réservation, horaires d’ouverture, conditions d’annulation et extras réservables avec zones de livraison.
{
"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" }]
}Unités libres par jour et créneaux de retrait et de retour en heure locale, jusqu’à 92 jours par requête. Jours de fermeture et horaires d’ouverture déjà pris en compte – idéal pour votre propre sélecteur de dates. La vérification définitive se fait via POST /v1/quotes et au paiement.
{
"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"]
}, …]
}Avis vérifiés d’un vélo, les plus récents d’abord, avec moyenne et nombre total. Les auteurs apparaissent avec prénom et initiale. Tous les avis d’un loueur : GET /v1/listers/{id}/reviews.
Profil public d’un loueur : nom, localisation, note, réservations réalisées, nombre de vélos, confirmation immédiate, règles de réservation, horaires d’ouverture et zones de livraison. Les loueurs particuliers apparaissent avec leur prénom et sans rue.
Les conditions d’annulation valables pour chaque réservation : à partir de 72 heures avant le retrait, tout est remboursé ; en dessous, une part de la location selon le créneau. Si le loueur annule, le client récupère tout.
Toutes les catégories avec leur nom allemand et anglais. Une catégorie parente comme e-bike inclut ses sous-catégories dans la recherche.
Tous les lieux avec des vélos réservables, ceux qui en ont le plus en premier. q cherche dans toutes les langues (p. ex. q=munich), country filtre par pays et locale choisit la langue des noms. Un lieu : GET /v1/places/{id}.
Au lieu d’un vélo précis, votre client réserve une classe – p. ex. « Vélo électrique, milieu de gamme » à Berlin – et ListNRide trouve un loueur adapté. Interrogez par place ou lat/lng. La réservation passe par une session de paiement avec class et size (taille du cycliste).
{
"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
}Calcule le prix exact comme le paiement ListNRide : location, remise, frais de service, assurance de base, options (insurance_plus) et livraison à une adresse – sans rien réserver. Un devis couvre les vélos d’un seul loueur ou une classe.
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 }Crée une session de paiement. Le paiement ListNRide vérifie le prix et la disponibilité. Le lien est valable 24 heures ; quantité et horaires sont présélectionnés au paiement.
| Champ | Description |
|---|---|
| ride * | ID du vélo ride_… |
| class, size | Au lieu de ride : une classe de GET /v1/classes et la taille du cycliste (165-175 … ou Unisize) |
| from, to * | Jour de retrait et de retour, YYYY-MM-DD |
| pickup_time, return_time | HH:MM, par défaut 10:00 / 17:00 |
| quantity | Quantité, 1–50, par défaut 1 |
| return_url * | Page de retour du client après la réservation (https), avec checkout_session, booking et status=success |
| cancel_url | Facultatif, en cas d’annulation (https) |
| locale | de · en · fr · es · it · nl |
| client_reference | Votre propre référence |
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://votre-site.fr/merci",
"locale": "fr"
}'
# → { "id": "cs_O8t1…", "amount_total": 7800,
# "url": "https://www.listnride.fr/api/go/p/BHTm…" }Statut de la session : open, booked (avec l’ID booking) ou expired.
| status | Description |
|---|---|
| awaiting_payment | Le client est au paiement, pas encore payé |
| requested | Payé ou réservé, en attente d’acceptation du loueur |
| accepted | Accepté par le loueur, paiement en cours |
| confirmed | Confirmé |
| completed | Location terminée |
| canceled_by_lister · canceled_by_customer · canceled | Annulé |
| expired | Non payé ou non accepté à temps |
Toutes les réservations issues de vos sessions de paiement, les plus récentes d’abord. Filtrez par status ou par votre client_reference. Une clé de test liste les réservations de test, une clé live les vraies. Les réservations annulées contiennent cancellation avec le montant et l’état du remboursement.
Annule une réservation au nom de votre client – selon les mêmes règles que sur listnride.com : à partir de 72 heures avant le retrait, tout est remboursé ; en dessous, une part de la location. Le loueur est prévenu, vous recevez booking.canceled_by_customer et le remboursement revient sur le moyen de paiement du client.
Vérifiez d’abord avec GET /v1/bookings/{id}/cancellation – indique si l’annulation est possible et le remboursement exact, sans rien modifier. L’annulation nécessite le scope bookings:cancel, activé sur demande. Facultatif : reason (changed_mind, found_better, timing_issue, price_too_high, personal_reasons, other) et comment.
# 1. Aperçu : l’annulation est-elle possible et combien le client récupère-t-il ?
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. Annuler
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"Ajoutez ?aff=VOTRECODE à n’importe quel lien ListNRide – toutes les pages, toutes les langues. Si le client réserve dans le délai convenu, la réservation vous est attribuée ; le dernier clic l’emporte. Les réservations issues de vos sessions de paiement vous sont toujours attribuées, même sans clic.
La commission est convenue individuellement et se base sur les frais que ListNRide perçoit sur la réservation. Elle est due une fois la location terminée ; si le loueur annule, il n’y a pas de commission. GET /v1/commissions affiche clics, réservations, palier et commission par mois – sans données clients. Le décompte est mensuel, par note de crédit.
# Lien partenaire – fonctionne sur toutes les pages
https://www.listnride.de/berlin/e-bike?aff=NEEDABIKE
# Votre commission pour un mois
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
Quand le statut d’une réservation change, nous envoyons un POST à votre URL de webhook, p. ex. booking.confirmed. Répondez avec un code 2xx – sinon nous réessayons après 1 min, 5 min, 30 min et jusqu’à 24 h. Utilisez ping pour tester la connexion ; l’id de l’événement reste identique lors des nouvelles tentatives.
Vérifiez chaque message avec l’en-tête LNR-Signature: t=…,v1=… : HMAC-SHA256 sur t + "." + body avec votre secret whsec_…. Utilisez le corps brut, non modifié, et rejetez les messages dont t date de plus de 5 minutes.
POST https://votre-site.fr/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: le corps brut, tel que reçu
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: le corps brut, tel que reçu
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", ""))Erreurs & limites
Les erreurs ont toujours la même forme. Grâce au request_id, nous retrouvons rapidement votre cas.
Limites par clé : une limite par minute et un quota journalier (en-têtes X-Quota-Limit, X-Quota-Remaining). Une recherche se parcourt au maximum sur 500 résultats – affinez-la par lieu, rayon, catégorie ou période. La collecte massive et la revente des données sont interdites.
Nouvelles tentatives sans risque : envoyez l’en-tête Idempotency-Key avec POST /v1/checkout/sessions et POST /v1/bookings/{id}/cancel. Une nouvelle tentative avec la même clé et le même contenu renvoie la première réponse (en-tête Idempotent-Replayed: true) au lieu d’agir deux fois. Les clés sont conservées 24 heures.
| 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 et outils
Clients officiels en un seul fichier, sans dépendances – copiez-les dans votre projet. Ils gèrent l’authentification, la pagination, les nouvelles tentatives en cas de 429/5xx, les Idempotency-Keys et la vérification des 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" }); // l’Idempotency-Key est ajoutée automatiquementVersions
La version figure dans le chemin. Au sein de /v1, nous ajoutons uniquement des champs – rien n’est supprimé ni renommé. Les changements majeurs paraîtront en /v2, et /v1 restera disponible au moins 12 mois. La description lisible par machine (OpenAPI 3.1) se trouve sur /openapi.json et https://api.listnride.com/v1/openapi.json.
Journal des modifications
Idempotency-Key pour les appels d’écriture, collection Postman, clients officiels pour Node.js, PHP et Python.
Affiliation : liens partenaires avec
?aff=CODEetGET /v1/commissions.GET /v1/bookings, aperçu d’annulation etPOST /v1/bookings/{id}/cancel(scopebookings:cancel).Filtres de recherche (prix, taille, équipement, zone de carte …), paliers de prix, horaires, conditions d’annulation, calendrier de disponibilité, avis et profils de loueurs.
Lieux, classes de véhicules,
POST /v1/quotes, réservation par classe et quota quotidien par clé.Lancement de v1 : vélos, catégories, sessions de paiement, réservations, webhooks et mode test.
Demander un accès
Présentez-nous votre site et votre projet. Vous recevez d’abord une clé de test – la mise en production suit après un court échange.
partner@listnride.com