Aller au contenu

Recevoir nos réservations

Quand un voyageur réserve sur Localoge, nous vous prévenons. Bloquez alors ces nuits chez vous, sans quoi vous continuerez à les proposer ailleurs.

Fenêtre de terminal
curl -X PUT https://localoge.com/api/v1/channel/webhooks \
-H "Authorization: Bearer $LOCALOGE_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://partenaire.example.com/webhooks/localoge" }'
{ "success": true, "data": { "id": "…", "url": "…", "secret": "whsec_9f2c…", "events": [] } }

HTTPS obligatoire. Une liste events vide veut dire tous les événements ; précisez-la pour n’en recevoir qu’une partie.

Nous refusons (400 INVALID_PAYLOAD) un nom d’événement inconnu, plutôt que de l’ignorer : une faute de frappe dans reservation.canceled vous priverait sinon des annulations sans un mot. Le message d’erreur liste les noms connus. Nous refusons aussi une URL qui ne se résout pas vers une adresse publique (localhost, 10.x, 192.168.x…) : exposez un point de réception public, ou utilisez le miroir pour vos premiers essais.

Un abonnement vaut pour une instance : celui déclaré avec votre clé lok_test_ sur le sandbox ne reçoit rien de la production, et inversement.

Dans votre espace développeur, ouvrez votre application, renseignez l’URL de webhook et enregistrez : le secret s’affiche, une seule fois, au même endroit. C’est le même mécanisme, la même signature, le même comportement. À utiliser si vous voulez recevoir vos premiers événements avant d’avoir écrit votre client d’API.

L’écran vous dit si la livraison est réellement branchée, et non seulement si une adresse est enregistrée. Un bouton y régénère le secret : l’ancien meurt à la seconde où le nouveau s’affiche, déployez-le chez vous immédiatement.

Événement Quand
reservation.created Un voyageur a réservé sur Localoge. Bloquez ces nuits chez vous.
reservation.updated Une réservation Localoge a changé (dates, voyageurs).
reservation.cancelled Une réservation Localoge est annulée : les nuits sont libres.
availability.updated L’hôte a modifié ses disponibilités directement sur Localoge.
property.updated Une annonce a changé.
property.status_changed Le statut d’une annonce a changé : publiée, en pause, en attente de validation. Voir Cycle de vie.
message.received Un message a été écrit dans la conversation d’un séjour. Voir Messagerie.
review.created Un avis a été publié sur un logement. La note est sur dix.
payment.succeeded Le loyer d’une réservation Localoge est encaissé (confirmé par notre prestataire de paiement).
payment.refunded Localoge a remboursé le voyageur d’une réservation Localoge, en totalité ou en partie.
host.revoked Un hôte vous a retiré son autorisation : son host_ref ne vaut plus rien. Cessez de pousser ses logements.
webhook.test Envoyé à la demande (POST /webhooks/test ou bouton de l’espace). Ne porte aucune donnée métier.

Nous ne vous renvoyons jamais les réservations que vous nous avez envoyées : vous les connaissez, et vous les rejoueriez chez vous.

Tout événement inconnu de votre code doit être accepté en 2xx et ignoré. Nous ajouterons des événements ; un 400 sur un nom nouveau ferait réessayer la livraison pendant trente heures.

{
"event": "reservation.created",
"event_key": "reservation.created:3f8a…",
"created_at": "2026-08-26T14:03:11.000Z",
"api_version": "v1",
"environment": "production",
"data": {
"reservation_id": "3f8a…",
"external_property_id": "PROP-4821",
"check_in": "2026-09-10",
"check_out": "2026-09-15",
"status": "confirmed",
"guests": 3,
"total": 72500,
"currency": "EUR",
"updated_at": "2026-08-26T14:03:11.000Z"
}
}

api_version vaut v1 pour toute la durée de vie de cette version. environment vaut sandbox ou production : vérifiez-le, et refusez un événement de sandbox arrivé sur votre point de réception de production.

Aucune donnée personnelle du voyageur ne vous est transmise : ni nom, ni adresse, ni téléphone. Vous avez besoin de savoir que des nuits sont prises, pas qui dort dans le lit. Seule exception : le texte d’un message.received, écrit par une personne.

Événement Champs de data
reservation.* reservation_id, external_property_id, check_in, check_out, status, guests, total (centimes), currency, updated_at
availability.updated external_property_id, dates (liste de YYYY-MM-DD)
property.updated external_property_id, listing_id, et status quand l’appel vient de vous
property.status_changed external_property_id, listing_id, status, previous_status, reason (facultatif, par exemple archived by partner), updated_at
message.received external_property_id, reservation_id (identifiant Localoge, ou null), from (guest / host), text, sent_at
review.created external_property_id, reservation_id, rating (sur 10), comment, published_at
payment.succeeded, payment.refunded reservation_id, external_property_id, amount (centimes : encaissé ou remboursé), reservation_total (centimes), currency, occurred_at
host.revoked host_ref, revoked_at
webhook.test message, sent_at

Les deux événements payment.* ne concernent que les réservations vendues sur Localoge : jamais une réservation que vous nous avez envoyée, puisque nous n’encaissons rien sur celles-là. Aucune donnée bancaire ne vous est transmise, seulement les montants.

{
"event": "payment.refunded",
"event_key": "payment.refunded:re_3Q…",
"created_at": "2026-09-29T16:20:00.000Z",
"api_version": "v1",
"environment": "production",
"data": {
"reservation_id": "3f8a…",
"external_property_id": "PROP-4821",
"amount": 30000,
"reservation_total": 72500,
"currency": "EUR",
"occurred_at": "2026-09-29T16:20:00.000Z"
}
}

event_key vaut payment.succeeded:<reservation_id> (un seul encaissement par réservation) et payment.refunded:<identifiant du remboursement> : plusieurs remboursements partiels d’une même réservation sont autant d’événements distincts. Un amount inférieur à reservation_total sur un payment.refunded signale un remboursement partiel.

La référence de l’API décrit chaque charge utile champ par champ.

L’en-tête X-Localoge-Signature porte t=<horodatage>,v1=<hmac>. Le HMAC-SHA256 est calculé sur <horodatage>.<corps brut>, avec votre secret.

import { createHmac, timingSafeEqual } from 'node:crypto';
function signatureValide(secret, corpsBrut, entete, toleranceSec = 300) {
const m = /^t=(\d+),v1=([0-9a-f]+)$/.exec(entete.trim());
if (!m) return false;
const t = Number(m[1]);
// L'horodatage entre dans le calcul : sans cette fenêtre, un envoi capté
// resterait rejouable indéfiniment.
if (Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const attendu = createHmac('sha256', secret).update(`${t}.${corpsBrut}`).digest('hex');
const a = Buffer.from(attendu, 'hex');
const b = Buffer.from(m[2], 'hex');
return a.length === b.length && timingSafeEqual(a, b);
}

Répondez 2xx dès réception, puis traitez en tâche de fond. Nous coupons à 10 secondes.

Toute réponse hors 2xx, et toute absence de réponse, est un échec que nous réessayons.

À 1 minute, 5, 15, 1 heure, 6 heures, puis 24 heures. Sept tentatives sur environ 30 heures, après quoi nous abandonnons et un humain est prévenu chez nous.

Un réessai porte le même event_key. Utilisez-le comme clé d’unicité de votre côté : c’est ce qui vous évite de traiter deux fois la même réservation quand notre première tentative a abouti chez vous mais que sa réponse s’est perdue.

L’en-tête X-Localoge-Event-Key porte la même valeur, si vous préférez ne pas lire le corps.

Chaque événement est une livraison que vous pouvez relire, avec son statut, son nombre de tentatives et la dernière réponse HTTP de votre serveur :

Fenêtre de terminal
curl "https://localoge.com/api/v1/channel/webhooks/deliveries?status=failed&limit=50" \
-H "Authorization: Bearer $LOCALOGE_KEY"
{
"success": true,
"environment": "production",
"data": {
"deliveries": [
{
"id": "d7c1…",
"event": "reservation.created",
"event_key": "reservation.created:3f8a…",
"status": "failed",
"attempts": 7,
"last_http_status": 500,
"last_response_ms": 812,
"last_error": null,
"next_attempt_at": null,
"last_attempt_at": "2026-09-29T15:12:44.000Z",
"delivered_at": null,
"created_at": "2026-09-28T09:12:44.000Z",
"payload": { "reservation_id": "3f8a…" }
}
],
"next_cursor": null
}
}

Les livraisons sont triées de la plus récente à la plus ancienne, 50 par page par défaut (200 au plus), et se parcourent avec next_cursor. status vaut pending (en attente, en cours d’envoi ou de réessai), delivered ou failed (abandonnée après sept tentatives). last_response_ms est le temps de réponse de votre serveur à la dernière tentative.

Une fois votre serveur réparé, remettez une livraison en file :

Fenêtre de terminal
curl -X POST https://localoge.com/api/v1/channel/webhooks/deliveries/d7c1…/retry \
-H "Authorization: Bearer $LOCALOGE_KEY"
{ "success": true, "environment": "production", "data": { "id": "d7c1…", "status": "pending" } }

Elle repart avec le même event_key, compteur de tentatives remis à zéro : votre déduplication la reconnaîtra si elle était en fait arrivée. 404 NOT_FOUND pour une livraison inconnue, 409 CONFLICT si elle est en cours d’envoi à cet instant.

Fenêtre de terminal
curl -X POST https://localoge.com/api/v1/channel/webhooks/test \
-H "Authorization: Bearer $LOCALOGE_KEY"
{
"success": true,
"environment": "production",
"data": { "event": "webhook.test", "event_key": "webhook.test:6c0e…", "status": "pending" }
}

Réponse 202 : l’événement est mis en file, puis part vers votre URL enregistrée, signé comme les autres. Son data vaut { "message": "Test event from Localoge", "sent_at": "…" }. C’est la façon la plus rapide de vérifier votre réception et votre signature sans créer de réservation. Sans webhook actif, la réponse est 409 CONFLICT.

Déclarez https://localoge.com/webhook-echo/<votre-identifiant> comme URL de réception (ou son équivalent sur https://sandbox.localoge.com), provoquez un événement, puis relisez ce que nous avons envoyé :

Fenêtre de terminal
curl https://localoge.com/api/v1/channel/webhook-echo \
-H "Authorization: Bearer $LOCALOGE_KEY"

Vous voyez les vingt dernières réceptions (conservées 24 heures), en-têtes compris, avec notre verdict sur la signature. Si elle est valide chez nous et refusée chez vous, le défaut est dans votre vérification. Pour éprouver votre refus d’une signature falsifiée, rejouez le corps reçu vers votre serveur avec un en-tête X-Localoge-Signature modifié : il doit répondre 4xx.

Fenêtre de terminal
curl "https://localoge.com/api/v1/channel/reservations?updated_since=2026-08-25T00:00:00Z" \
-H "Authorization: Bearer $LOCALOGE_KEY"

updated_since porte sur la date de modification : une réservation annulée depuis ressort avec status: "cancelled". Voir Pagination.

Plus général encore, GET /events rend tous les événements émis pour vous, livrés ou non, du plus ancien au plus récent, dans le même format que les webhooks (id, event, event_key, created_at, data). Son filtre de date s’appelle since (date de création de l’événement) :

Fenêtre de terminal
curl "https://localoge.com/api/v1/channel/events?since=2026-09-28T00:00:00Z&limit=200" \
-H "Authorization: Bearer $LOCALOGE_KEY"

À appeler après une panne de votre côté, ou une fois par jour par sécurité. Les webhooks sont le chemin rapide, celui-ci est le filet.