Cette page suffit pour démarrer. Le détail exhaustif est dans la référence, et la spécification machine sur openapi.json — importable telle quelle dans Postman.
1. Démarrer en 3 minutes
Une clé ne peut faire que ce que vous avez coché. Si vous confiez une clé à un prestataire pour alimenter un tableau de bord, ne cochez que la lecture : il ne pourra rien modifier, même par erreur.
Votre premier appel
Il ne touche à aucune donnée — il vous dit seulement si la clé fonctionne et ce qu'elle a le droit de faire.
curl https://app.nodegroupe.com/api/v1/me \ -H "Authorization: Bearer node_sk_..."
Faites-le avant d'écrire votre intégration : découvrir une autorisation manquante en pleine boucle de traitement coûte bien plus cher.
Un compte Pack 1 ne peut pas créer de nouvelle clé — l'écran vous le dit, le bouton est désactivé. Les clés créées avant le 1er septembre 2026 restent valables quel que soit votre pack : une décision de tarification ne coupe pas une intégration déjà en service.
Elle a été créée avant les autorisations et peut tout faire sur votre compte, y compris supprimer des réservations. Cochez ce dont elle a besoin, puis Restreindre : la clé reste valable, vous n'avez rien à reconfigurer.
2. Les 3 règles à connaître
Elles expliquent la quasi-totalité des intégrations qui coincent.
① Écrire un prix ou une disponibilité répond 202, pas 200
Vous recevez un job_id. À cet instant, rien n'est encore parti chez Airbnb ou Booking.
Node ne parle pas directement aux plateformes : il passe par un gestionnaire de canaux dont le débit est partagé entre tous les clients de Node. Une écriture immédiate depuis l'extérieur ralentirait la synchronisation de tout le monde. Vos modifications sont donc mises en file et poussées par lots, en quelques minutes.
# Suivez l'avancement — toutes les 10 à 30 secondes, pas plus souvent GET /api/v1/jobs/{job_id} # status : pending → processing → completed | failed
Un seul échec parmi les opérations marque le travail failed : annoncer « terminé » alors qu'une partie des dates n'est pas partie serait le pire des mensonges pour un calendrier.
② Écrivez par lot, jamais date par date
// ✅ UN appel, plusieurs plages — jusqu'à 60 PUT /api/v1/rates { "property_id": "…", "ranges": [ { "from": "2027-07-01", "to": "2027-08-31", "price": "180.00", "min_stay": 5 }, { "from": "2027-09-01", "to": "2027-10-31", "price": "120.00" } ] } // ✅ Les mêmes plages sur PLUSIEURS logements — jusqu'à 50 par appel PUT /api/v1/availability { "property_ids": ["…", "…", "…"], "ranges": [ { "from": "2027-12-20", "to": "2027-12-27", "available": false } ] } // → 202 + "jobs": [{ "property_id", "job_id" }, …] — un suivi par logement // ❌ JAMAIS ça : quota épuisé en secondes, envois rejetés for (const date of dates) PUT /api/v1/rates { ranges: [{ from: date, to: date }] }
Partie future comprise. Ce n'est pas une coquetterie : les plateformes rejettent la plage complète, et laisser passer vous donnerait un calendrier que vous croyez à jour alors qu'il ne l'est pas — c'est comme ça qu'on se retrouve en surréservation. Découpez à partir d'aujourd'hui.
③ Faites-vous prévenir, n'interrogez pas en boucle
Pour savoir qu'une réservation est arrivée, déclarez un point de réception : Node vous appelle. Le paramètre updated_since sert au rattrapage après une panne de votre côté, pas à la détection continue.
3. Tous les appels
Le détail de chacun — paramètres, réponse, erreurs, recommandations — est dans la référence complète.
| Appel | Ce que ça fait | Autorisation |
|---|---|---|
GET /v1/me | Vérifier la clé et ses autorisations | aucune |
GET /v1/me/modules | Modules allumés pour ce compte (navigation d'un espace marque blanche) | aucune |
GET /v1/properties | Lister les logements — filtres ids, updated_since, status | properties:read |
POST /v1/properties | Créer un logement | properties:write |
GET /v1/properties/{id} | Détail d'un logement | properties:read |
PATCH /v1/properties/{id} | Modifier un logement | properties:write |
GET /v1/owners | Lister les propriétaires | owners:read |
POST /v1/owners | Créer un propriétaire | owners:write |
GET /v1/reservations | Lister les réservations — filtres updated_since, property_ids, arrival_from/to, departure_from/to, status, channel | reservations:read |
GET /v1/reservations/{id} | Une réservation — à appeler après un webhook | reservations:read |
POST /v1/reservations | Réservation directe ou blocage | reservations:write |
GET /v1/channels | Valeurs possibles du canal d'une réservation | reservations.planning:read |
GET /v1/calendar | Disponibilités + tarifs de 50 logements × 400 jours en un appel | availability:read rates:read |
GET /v1/availability | Lire le calendrier | availability:read |
PUT /v1/availability202 | Ouvrir ou fermer des dates — 1 à 50 logements, 60 plages | availability:write |
GET /v1/rates | Lire prix et restrictions | rates:read |
PUT /v1/rates202 | Écrire prix et restrictions — 1 à 50 logements, 60 plages | rates:write |
GET /v1/jobs/{id} | Suivre une écriture asynchrone | aucune |
GET /v1/cleaning/missions | Lister les missions de ménage | cleaning:read |
POST /v1/cleaning/missions | Créer une mission | cleaning:write |
GET /v1/incidents | Lister les incidents (lecture seule) | cleaning:read |
GET /v1/invoices | Factures propriétaire — lecture seule | billing:read |
GET /v1/messages | Conversations et messages | messages:read |
POST /v1/messages | Écrire à un voyageur | messages:send |
GET /v1/webhooks | Points de réception + catalogue d'événements | webhooks:manage |
POST /v1/webhooks | Déclarer un point de réception | webhooks:manage |
POST /v1/catalogue/propositions | Proposer une extension de son espace au catalogue Node | catalogue:propose |
GET /v1/espace/donnees | Inventaire des données de l'espace | espace.donnees:read |
GET /v1/espace/donnees/{collection} | Lister les documents d'une collection | espace.donnees:read |
POST /v1/espace/donnees/{collection} | Créer un document | espace.donnees:write |
GET /v1/espace/donnees/{collection}/{id} | Lire, modifier (PATCH) ou supprimer (DELETE) un document | espace.donnees:write |
GET /v1/espace/secrets/{nom} | Lire une clé confiée par la conciergerie à son espace (coffre à secrets) | espace.secrets:read |
GET /v1/espace/domaines | Domaines externes que l'espace peut joindre | espace.secrets:read |
GET /v1/espace/automatisations | Automatisations de l'espace, état et journal | espace.automatisations:write |
POST /v1/espace/automatisations/journal | Inscrire le résultat d'une exécution | espace.automatisations:write |
POST /v1/envois/email | Envoyer un e-mail au nom de la conciergerie (200 par jour) | envois.email:send |
GET /v1/webhooks/{id} | État + 20 dernières livraisons | webhooks:manage |
PATCH /v1/webhooks/{id} | Changer les événements, la description, réactiver (même secret) | webhooks:manage |
DELETE /v1/webhooks/{id} | Retirer un point de réception | webhooks:manage |
GET /v1/prospection/leads | Lister les dossiers propriétaires | prospection:read |
POST /v1/prospection/leads | Créer un dossier (site web, campagne publicitaire) | prospection:write |
GET /v1/prospection/leads/{id} | Lire un dossier | prospection:read |
PATCH /v1/prospection/leads/{id} | Compléter ce qu'on a appris | prospection:write |
POST /v1/prospection/leads/{id}/advance | Demander une avancée d'étape | prospection:write |
GET /v1/validations | Actes régulés en attente de validation (carte G) | validations:read |
GET /v1/validations/{id} | Le détail d'un acte : avant / après, champ par champ | validations:read |
POST /v1/validations/{id}/decision | Approuver ou refuser à la place du propriétaire | validations:decide |
Créez une clé qui ne coche que prospection:write : elle crée des dossiers, elle n'en lit aucun. Si elle fuite, elle ne donne accès à rien.
Ne mettez jamais la clé dans la page. Tout ce qui part dans le navigateur est lisible par le visiteur : une clé posée dans le JavaScript d'un formulaire est publique dès la première visite. Le formulaire envoie à votre serveur, qui relaie à Node — ou passez par un connecteur (Zapier, Make, n8n) qui garde le secret de son côté. C'est aussi la seule méthode possible depuis un formulaire publicitaire Meta ou Google, qui ne sait pas appeler une API protégée.
L'étape ne s'écrit pas, elle se demande. stage est calculée à partir de ce qui est réellement renseigné ; l'envoyer ne produit aucune erreur, le champ est simplement ignoré. Pour faire avancer un dossier : POST /v1/prospection/leads/{id}/advance, qui répond en nommant le verrou qui retient.
Les doublons sont rattrapés. Un même e-mail ou téléphone déjà présent sur 30 jours renvoie 200 avec le dossier existant et deduplicated: true — pas une erreur. Les numéros sont comparés sur leurs neuf derniers chiffres, +33 6… et 06… étant le même.
Pagination par curseur, jamais par numéro de page : ?limit=100 puis ?cursor=… tant que has_more est vrai. Un offset dérive dès qu'une ligne s'insère pendant votre boucle — vous sauteriez des enregistrements sans le savoir.
Un en-tête Idempotency-Key sur tout POST : rejouer la même clé sous 24 h renvoie la première réponse au lieu de créer un doublon.
3 bis. Synchroniser en masse
Pour un outil qui tient sa propre copie des données — gestion des revenus, comptabilité, reporting : importer une fois, puis ne relire que ce qui a changé.
Le schéma en trois temps
| Étape | Appels |
|---|---|
| Import initial à l'arrivée d'un client | GET /v1/properties (paginé)GET /v1/reservations?property_ids=…&departure_from=2024-01-01&departure_to=2028-12-31GET /v1/calendar?property_ids=…&from=…&to=… (fenêtres de 400 jours) |
| Synchronisation quotidienne ou à chaque webhook | GET /v1/properties?updated_since=…GET /v1/reservations?updated_since=…GET /v1/calendar?property_ids=…&from=…&to=…&updated_since=… |
| Rapprochement ponctuel | Relire les identifiants sur une période (GET /v1/properties, GET /v1/reservations?departure_from=…) et comparer : une réservation annulée reste visible avec status: "cancelled" et cancelled_at — rien ne disparaît sans trace. |
Gardez la date du début de votre synchronisation précédente comme prochain updated_since (pas celle de la fin) : un enregistrement modifié pendant votre passage serait sinon perdu.
Le calendrier en un appel
GET /v1/calendar réunit disponibilités et tarifs : jusqu'à 50 logements × 400 jours. Par jour : available, booked, blocked, price, currency, min_stay, max_stay, closed_to_arrival, closed_to_departure, stop_sell, updated_at. Les valeurs du jour sont celles du plan tarifaire principal ; include_rate_plans=true ajoute le détail par plan.
updated_since sur le calendrier est large, pas exactLe calendrier est relu régulièrement auprès du gestionnaire de canaux : un jour relu sans changement peut réapparaître. Vous ne manquerez aucun changement, mais dédoublonnez de votre côté.
Le détail tarifaire d'une réservation
Avec reservations:read, chaque réservation porte un objet pricing : currency, accommodation (séjour seul), ota_commission, tourist_tax, cleaning_fee, net_owner, et fees — les frais détaillés transmis par la plateforme (linge, animaux, personne supplémentaire…, surtout Airbnb). S'y ajoutent booked_at (date de réservation réelle), status_detail (blocked pour un blocage) et is_block.
Les valeurs possibles de channel sont renvoyées par GET /v1/channels : de quoi construire votre table de correspondance une fois pour toutes.
Vos prix ne sont pas écrasés
Un prix écrit par PUT /v1/rates est inscrit comme fixé à la main : le moteur de tarification de Node ne le réécrit pas. La conciergerie le voit dans « Règles enregistrées » et peut le réinitialiser.
Accès et quotas
| Accès | Lectures / min | Écritures / min | Écritures calendrier / min |
|---|---|---|---|
Clé de la conciergerie (node_sk_…, Paramètres → API & MCP) | 600 | 60 | 10 |
Application partenaire OAuth2 (node_at_…, une connexion par client) | 3 000 | 300 | 30 |
- Les quotas sont par clé : chaque client a les siens, synchronisez-les en parallèle.
- Chaque réponse porte
RateLimit-Limit,RateLimit-RemainingetRateLimit-Reset; un429porteRetry-After. - OAuth2 : code d'autorisation + PKCE, jeton d'accès de 2 h, jeton de renouvellement de 90 jours. Pour obtenir une application partenaire, écrivez au support avec votre URL de redirection.
- Une écriture calendrier couvre 60 plages × 50 logements : 10 appels par minute suffisent largement.
4. Être prévenu — les webhooks
Sans eux, savoir qu'une réservation est arrivée impose d'interroger l'API en boucle. Et vous ne serez jamais prévenu plus tôt qu'avec un webhook.
POST /api/v1/webhooks { "url": "https://mon-service.fr/hooks/node", "events": ["reservation.created", "reservation.cancelled"] }
23 événements : réservations, arrivées et départs, messages voyageur, missions de ménage, factures, logements, calendrier et prix, incidents, validations. Le catalogue complet est renvoyé par GET /v1/webhooks : vous pouvez construire votre écran d'abonnement à partir de cette seule réponse.
Calendrier et prix
Pour garder un site de réservation à jour sans interroger l'API en boucle :
| Événement | Quand | Corps (data) | Portée |
|---|---|---|---|
availability.updated | Dates ouvertes, fermées ou réservées, sur n'importe quel canal | property_id, start_date, end_date | availability:read |
rates.updated | Prix par nuit ou règle de séjour modifié, sur n'importe quel plan tarifaire | property_id, start_date, end_date | rates:read |
property.deleted | Logement supprimé | property_id | properties:read |
- L'événement est un signal : relisez
GET /v1/availabilityetGET /v1/ratessur la plage reçue (dates incluses). - Regroupé par logement : 30 modifications d'affilée donnent un seul événement, envoyé 30 secondes après la dernière (5 minutes au plus après la première), dont la plage couvre toutes les dates touchées.
- Un changement fait directement dans l'extranet de l'OTA ou dans Channex n'émet rien tant que Node ne l'a pas relu. Gardez une synchronisation quotidienne en filet de sécurité.
Modifier un abonnement
PATCH /api/v1/webhooks/{id} { "events": ["reservation.created", "availability.updated", "rates.updated"] }
events remplace la liste entière : pour ajouter un événement, renvoyez la liste actuelle plus le nouveau. Le secret ne change pas, rien à redéployer chez vous. enabled: true réactive un point de réception coupé. L'URL et le secret ne se modifient pas : pour en changer, créez un nouveau point de réception. Un jeton ne modifie que les points de réception qu'il a créés.
Votre URL est publique : elle finit dans des logs, des captures d'écran, des tickets. La signature Node-Signature est la seule chose qui distingue un événement de Node d'un événement fabriqué. Le code de vérification, en JavaScript et en Python, est dans la référence.
⚠️ Signez le corps brut, avant tout parsing : un JSON.parse puis JSON.stringify réordonne les clés et invalide la signature.
| Garantie | Ce que ça implique pour vous |
|---|---|
| Au moins une livraison, jamais exactement une | Dédoublonnez sur l'en-tête Node-Event-Id, stable entre les tentatives |
| Reprises espacées : 1 min, 5, 30, 2 h, 6 h, 24 h | Une panne courte de votre côté ne perd rien |
| 20 échecs consécutifs coupent le point de réception | Aucun e-mail n'est envoyé : surveillez disabled_at sur GET /v1/webhooks/{id}. Réactivez-le avec PATCH /v1/webhooks/{id} et {"enabled": true} : le compteur repart de zéro |
| Réponse attendue en moins de 10 secondes | Répondez 2xx tout de suite, traitez en tâche de fond |
GET /v1/webhooks/{id} renvoie les 20 dernières livraisons avec code de réponse et message d'erreur. C'est la première chose à regarder avant d'ouvrir un ticket « je ne reçois rien ».
5. Quand ça ne marche pas
| Réponse | Signification | Que faire |
|---|---|---|
400 | Paramètre absent ou mal formé | Le champ field dit lequel |
401 | Clé absente, mal copiée, expirée ou révoquée | Vérifier la clé |
403 scope_missing | L'autorisation n'est pas cochée | Le message nomme la portée manquante |
403 PACK2_REQUIRED | L'API est incluse au Pack 2 | Votre compte est au Pack 1 |
404 | Introuvable — ou hors du périmètre de votre clé | Vérifier l'identifiant |
422 | Valide mais inapplicable | Ex. logement non connecté aux canaux |
429 | Trop d'appels | Respectez Retry-After — réessayer tout de suite aggrave la situation |
Chaque réponse porte un en-tête Node-Request-Id. Citez-le dans votre demande au support : il retrouve votre appel exact, à la seconde près.
6. Ce que l'API ne fait pas
Chaque refus a une raison, et la voici.
| Pas possible | Pourquoi |
|---|---|
| Supprimer une réservation ou un logement | La suppression libère les dates chez les plateformes sans laisser de trace. Passez le statut à cancelled : c'est tracé et réversible. |
| Modifier une réservation Airbnb, Booking ou d'une autre plateforme | Elle appartient à la plateforme : une modification faite ailleurs serait écrasée au prochain échange. Seules les réservations directes et les blocages s'écrivent ici. |
| Donner frais de gestion, TVA, commission voyageur, remboursements, promotions ou frais de paiement d'une réservation | Node ne les reçoit pas de façon fiable des plateformes. Plutôt que des montants inventés, ces lignes sont absentes de pricing. |
| Écrire sur la facturation ou les paiements | Commissions, TVA et taxe de séjour s'y croisent : une erreur d'intégration deviendrait une erreur comptable. Lecture seule. |
| Lire les identifiants de vos comptes OTA | Ni les vôtres, ni ceux de personne. Leur fuite compromettrait vos comptes sur les plateformes. |
| Accéder aux données d'un autre compte | Aucune portée d'administration, aucun accès inter-comptes. |
| Utiliser une clé depuis un navigateur | Un secret dans une page est un secret public. L'API est serveur à serveur. |
7. Support
Ouvrez un ticket depuis Node en citant :
- le
Node-Request-Idde la réponse (ou leNode-Event-Idpour un webhook) ; - l'horodatage ;
- le début de votre clé (
node_sk_AbC1…) — jamais le secret complet.
Ces trois éléments suffisent à retrouver votre appel exact dans le journal.