Documentation bêta

API RéservPro

Catalogue, réservations, paiements, contrôle des accès et opérations de l’équipe. Une fiche par endpoint, organisée par domaine.

Authorization: Bearer Paiement hébergé Webhooks HMAC SHA-256

Documentation API

Vue d’ensemble

L’intégration partenaire sépare le panier et le paiement. Le partenaire ajoute ou modifie les réservations dans une session, puis crée un checkout. RéservPro calcule les montants, héberge la saisie du paiement et publie l’état autoritaire par API et par webhook.

Lecture

  • Catégories et nombre de services
  • Liste des services
  • Détail d’un service
  • Variations tarifaires et restrictions
  • Emplacements d’un service
  • Calendrier rapide des jours complets

Écriture

  • Ajout d’une réservation dans une session
  • Modification d’une réservation existante
  • Transmission des informations complètes du client
  • Création idempotente d’un checkout
  • Paiement sécurisé dans une iframe RéservPro
  • Suivi par polling et webhooks signés
Flux recommandé : disponibilité → POST /api/reservation avec ajouter ou modifier → POST /api/checkout → affichage de iframe_html ou payment_url → webhook et GET /api/checkout.

Exemples pour les outils externes

Télécharger les exemples de réponses en JSON. Ce fichier contient uniquement des données fictives et illustre les structures. Les fiches détaillent les champs conditionnels, les types et les erreurs.

Authentification

Toutes les requêtes doivent être effectuées de serveur à serveur avec la clé du compte marchand. La méthode recommandée est l’en-tête HTTP Authorization: Bearer.

curl 'https://beta.reservpro.com/api/services?Limite=20' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer VOTRE_CLE_API'
Important : le partenaire ne transmet jamais IDEntreprise. RéservPro le déduit de la clé. La clé ne doit jamais être intégrée au JavaScript, à l’iframe, à une application cliente distribuée ni enregistrée dans les journaux.
Compatibilité dépréciée : le paramètre api dans la query string ou le corps est encore accepté temporairement, mais peut apparaître dans les journaux et historiques. Toute nouvelle intégration doit utiliser Bearer. Une requête contenant des clés différentes dans plusieurs emplacements est refusée.

Format de réponse standard

{
  "success": true,
  "error": false,
  "endpoint": "services",
  "IDEntreprise": 123,
  "request_id": "req_…",
  "data": { ... }
}

Où se trouvent les données?

ChampType JSONDescription
/api/categoriesdata.details[]Catégories.
/api/servicesdata.Resultats[]Pagination dans data.details.
/api/servicedata.ServiceVérifier aussi data.Existe.
/api/variationsdata.variations[] ou data.periodes[]Selon data.mode.
/api/emplacementsdata.services[].Emplacements[]Pagination dans data.details.
/api/calendrierdata.jours[]Clés date et disponible en minuscules.
/api/disponibilitedataVérifier Disponible et Erreur, pas seulement success.
/api/reservationdataPanier ou résultat de l’action, selon la méthode.
/api/checkoutcheckoutException : l’objet checkout est à la racine, pas dans data.
/api/gate-accessdataVérifier valid avant d’autoriser le passage.
/api/gate-codesdata.codes[]Codes avec leur contexte.
/api/gate-historydata.Historique[]Passages du code exact.
/api/departs et /api/taches GETdata.Resultats[]Pagination directement dans data.
/api/taches PATCH et /api/emplacement-statutdataRésultat de transition ou état effectif.

Les schémas historiques ne sont pas uniformes. Les exemples de chaque fiche montrent le format effectivement servi. Les champs supplémentaires doivent être tolérés par les clients pour permettre les enrichissements compatibles.

Sécurité, formats et limites

ProtectionLimiteComportement
Corps de requête64 Kio (65 536 octets)Au-delà : 413 payload_too_large. Pour un POST JSON, utiliser Content-Type: application/json.
Débit par adresse IP600 requêtes par minuteAu-delà : 429 rate_limit_exceeded.
Débit par compte marchand300 requêtes par minuteLe quota est partagé entre les intégrations utilisant la même clé.
Clés invalides5 échecs sur 5 minutesL’adresse IP est bloquée pendant 15 minutes.

Les réponses incluent un X-Request-ID. Les réponses limitées utilisent 429 et Retry-After; les réponses authentifiées exposent aussi X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset.

Données de carte interdites : ne jamais envoyer numéro de carte, date d’expiration, CVV/CVC, PAN ou jeton de carte dans l’API, dans customer ou dans metadata. Ces données sont saisies uniquement dans la page de paiement hébergée par RéservPro.

Contrat structuré de la bêta — 9 septembre 2026

Les périodes d’ouverture sont des objets avec DateDebut et DateFin. Les prix, frais, dépôts et taxes calculées sont des nombres JSON ou null, sans symbole monétaire. Les taux restent des pourcentages numériques. Les types tarifaires utilisent un slug stable et un libellé séparé.

Les intégrations utilisant l’ancienne bêta doivent adapter la lecture de DatesOuvertures, PeriodeReservationGenerale, PrixHoraire et des montants. PrixBaseFormate est retiré du contrat partenaire; utiliser PrixBase. Type_Tarification est remplacé par type_tarification et type_tarification_texte. Ces changements ne sont pas déployés en production.

Index des endpoints

Choisissez un domaine puis une fiche. Chaque endpoint conserve son lien direct.

Catégories

GET/api/categoriesLecture

Retourne les catégories principales, précisions ou sous-précisions. Possibilité de filtrer les catégories ayant des services actifs.

Paramètres

NomTypeRequisDescription
parentstringNonID du parent, ex. C12 ou P5.
mots_clesarray|stringNonMots-clés de recherche.
avecServiceActifboolNonSi vrai, retourne seulement les catégories qui ont au moins un service actif.

Exemple

GET /api/categories?avecServiceActif=1
Authorization: Bearer VOTRE_CLE_API

Réponse HTTP 200 vérifiée

{
  "success": true,
  "error": false,
  "endpoint": "categories",
  "IDEntreprise": 9379,
  "data": {
    "details": [
      {
        "id": "C346",
        "titre": "Activités",
        "icone": "fa-basketball",
        "nbr_services": 4,
        "have_child": true,
        "parent_id": null,
        "parent_titre": null
      },
      {
        "id": "C303",
        "titre": "Camping",
        "icone": "fa-campground",
        "nbr_services": 5,
        "have_child": true,
        "parent_id": null,
        "parent_titre": null
      },
      {
        "id": "C304",
        "titre": "Chalet",
        "icone": "fa-house",
        "nbr_services": 1,
        "have_child": true,
        "parent_id": null,
        "parent_titre": null
      },
      {
        "id": "C371",
        "titre": "Événements ",
        "icone": "fa-calendar-day",
        "nbr_services": 4,
        "have_child": true,
        "parent_id": null,
        "parent_titre": null
      },
      {
        "id": "C362",
        "titre": "Passeport",
        "icone": "fa-passport",
        "nbr_services": 3,
        "have_child": true,
        "parent_id": null,
        "parent_titre": null
      }
    ]
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.detailsarray<object>Catégories retournées, [] si aucune. Pas de pagination sur cette route.
idstringIdentifiant préfixé C, P ou S, utilisable dans IDCategorie et parent.
titre / iconestring | nullLibellé et icône configurés.
couleurstring | null · conditionnelCouleur d’icône pour les précisions et sous-précisions.
nbr_servicesintegerNombre calculé dans la branche. La branche S retourne actuellement 0 : ne pas interpréter cela comme un inventaire vide.
have_childbooleanIndication de navigation. Les précisions P peuvent retourner false même si la route parent=P… expose des sous-précisions; ne pas en faire une preuve d’absence.
parent_id / parent_titrestring | nullParent, ou null à la racine.

Les libellés et nombres de catégories ne remplacent pas la liste filtrée des services effectivement réservables. Charger /api/services pour construire le catalogue.

Liste des services

GET/api/servicesLecture

Retourne les services de l’entreprise avec recherche par mots-clés, pagination et filtres de visibilité/réservabilité.

Paramètres

NomTypeDescription
Mot_ClesstringRecherche texte libre.
IDCategoriestringEx. C2, P5, S9.
DebutintOffset de pagination.
LimiteintNombre max de résultats.
Service_Publieint1 = publié.
Service_Reservable_Publicint1 = réservable en ligne.
Service_Reservable_Interneint1 = réservable à l’interne.
En_Vedetteint1 = en vedette.

Exemple

GET /api/services?Service_Publie=1&Service_Reservable_Public=1&Debut=0&Limite=20
Authorization: Bearer VOTRE_CLE_API

Structure de réponse et exemple HTTP 200

Réponse Démo Camping vérifiée le 9 septembre 2026 avec Limite=1, sans filtre de réservation publique. Les lignes sont dans data.Resultats; la pagination dans data.details.

{
  "success": true,
  "error": false,
  "endpoint": "services",
  "IDEntreprise": 9379,
  "data": {
    "details": {
      "Message": "",
      "Total": 18,
      "Debut": 0,
      "Limite": 1,
      "InclutServicesSupprimes": false,
      "InstructionAria": "",
      "TravailEnLot": []
    },
    "Resultats": [
      {
        "IDService": 31139,
        "Titre": "Inventaire Kayak",
        "Image": null,
        "Description_Courte": "",
        "Categorie_Texte": "",
        "IDCategorie": "",
        "IDSousCategorie": "",
        "IDSousSousCategorie": "",
        "TypeService": 2,
        "EstHebergement": false,
        "Prix": 0,
        "Quantite": 5,
        "Service_Publie": 1,
        "Service_Reservable_Public": 0,
        "Service_Reservable_Interne": 1,
        "Approbation_Manuelle": 0,
        "En_Vedette": 0,
        "NombreEmplacements": 5,
        "NombreHoraires": 0,
        "DatesOuvertures": []
      }
    ]
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.details.Total / Debut / LimiteintegerTotal et pagination. Debut commence à 0; Limite=20 par défaut, entre 1 et 100.
data.details.MessagestringPrécision sur la recherche, éventuellement vide.
data.details.InclutServicesSupprimesbooleanIndicateur de recherche spéciale des services supprimés.
data.details.InstructionAria / TravailEnLotstring / array ou objectContexte auxiliaire Aria, normalement vide pour une requête partenaire. Ne pas utiliser pour construire le catalogue.
data.Resultatsarray<object>Services de la page; [] si aucun résultat.

Champs de data.Resultats[]

ChampType JSONDescription
IDServiceintegerIdentifiant du service.
Titrestring | nullTitre enregistré.
Imagestring | nullURL de l’image principale ou null. La fiche utilise Images[].
Description_Courtestring | nullRésumé enregistré, éventuellement vide ou null.
Categorie_TextestringChemin lisible de la catégorie.
IDCategoriestringIdentifiant préfixé C ou chaîne vide.
IDSousCategoriestringIdentifiant préfixé P ou chaîne vide.
IDSousSousCategoriestringIdentifiant préfixé S ou chaîne vide.
TypeServiceintegerMode natif (nom différent de TypeReservation dans la fiche).
EstHebergementbooleanClassement hébergement de la catégorie, distinct du mode de réservation.
Prixnumber | nullPrix numérique sans symbole; null si le moteur n’a pas fourni de prix. La fiche fournit PrixBase.
QuantiteintegerEn horaire : nombre d’emplacements (1 par défaut); autrement : quantité configurée bornée à 0. Pas la disponibilité datée.
Service_PublieintegerIndicateur numérique : 1 = publié.
Service_Reservable_PublicintegerIndicateur numérique : 1 = réservable en ligne.
Service_Reservable_InterneintegerIndicateur numérique : 1 = réservable à l’interne.
Approbation_ManuelleintegerIndicateur numérique : 1 = approbation manuelle.
En_VedetteintegerIndicateur numérique : 1 = en vedette.
NombreEmplacementsintegerNombre d’unités configurées.
NombreHorairesintegerNombre d’horaires configurés.
DatesOuverturesarray<object>Périodes avec DateDebut et DateFin (YYYY-MM-DD), ou [].
PrixHorairearray<object> · conditionnelTarifs horaires structurés : DureeHeures (number) et Montant (number ou null), sans texte concaténé.
Différences avec la fiche : TypeService, Quantite, Prix et Image deviennent TypeReservation, Quantité, PrixBase et Images. Les noms restent distincts, mais les prix sont numériques dans les deux routes.

Une recherche par mot-clé peut se rabattre sur les emplacements : details.Message l’indique et les lignes peuvent être réduites à IDService, Titre, Categorie, TypeService, Prix (null) et Quantite (0). Charger alors la fiche détaillée.

Détail d’un service

GET/api/serviceLecture

Retourne les détails complets d’un service : description, tarification, images, dépôt, ouverture, taxes, options de réservation et rates OTA si applicables.

Paramètres

NomTypeRequisDescription
IDServiceintOuiID du service.
InclureParametresVidesboolNonDéfaut : false. Conserve les attributs sans réponse ni choix sélectionné; voir leur structure ci-dessous.
GET /api/service?IDService=35197
Authorization: Bearer VOTRE_CLE_API

Lire la réponse

Chemin : data.Service. Vérifier success, puis data.Existe. La liste /api/services utilise data.Resultats[].

Exemple de réponse HTTP 200

Réponse HTTP de Démo Camping vérifiée en bêta le 9 septembre 2026. Un seul attribut complémentaire est conservé pour la lisibilité et request_id est remplacé. Les valeurs peuvent évoluer; utilisez un IDService de votre compte.

{
  "success": true,
  "error": false,
  "endpoint": "service",
  "IDEntreprise": 9379,
  "data": {
    "Existe": true,
    "Service": {
      "IDService": 27644,
      "Titre": "Camping 1 service (eau)",
      "Categorie_Texte": "Camping > Camping 1 service",
      "IDCategorie": "C303",
      "IDSousCategorie": "P1680",
      "IDSousSousCategorie": "",
      "Description": "<p>\r\n\t86 sites de camping am&eacute;nag&eacute;s dont 28 sans service avec eau &agrave; proximit&eacute; et 58 sites avec 1 service (eau sur le site).</p>\r\n",
      "Quantité": 50,
      "TypeReservation": 0,
      "EstHebergement": true,
      "TypeJours": 0,
      "PrixBase": 38,
      "SourcePrixBase": "vit_pac.prop_price",
      "ReglePrixBase": "Pour un calcul fondé sur le prix de base du service, utiliser PrixBase. Ne pas le remplacer par un montant de DetailsComplementaires, une variation de calendrier, un tarif saisonnier ou un prix futur.",
      "Images": [
        {
          "IDPhoto": 50577,
          "URL": "https://beta.reservpro.com/pac/50577.png"
        }
      ],
      "Ouverture": "Arrivée possible tous les jours",
      "Tarification": [
        {
          "Montant": 38,
          "type_tarification": "par_nuit",
          "type_tarification_texte": "Prix par nuit",
          "SurDemande": false
        },
        {
          "Montant": 1370,
          "type_tarification": "saisonnier",
          "type_tarification_texte": "Prix saisonnier",
          "SurDemande": false
        }
      ],
      "DatesOuvertures": [
        {
          "DateDebut": "2026-03-01",
          "DateFin": "2026-12-31"
        }
      ],
      "PeriodeReservationGenerale": {
        "DateDebut": "2026-03-01",
        "DateFin": "2026-12-31"
      },
      "Reservation_en_ligne": "Activé",
      "Reservation_interne": "Activé",
      "Approbation_manuelle": "Désactivé",
      "Etat": "Publié",
      "Nuit_Minimum": 2,
      "Nuit_Maximum": 0,
      "Duree_Minimum_WEEK_END": 0,
      "Depot_En_Ligne_Pourcentage": 20,
      "Depot_Local_Pourcentage": 0,
      "Depot_En_Ligne": 0,
      "Depot_En_Ligne_Par_Nuit": 0,
      "Depot_En_Ligne_Par_Semaine": 0,
      "Demander_Age_Enfants": true,
      "Demander_Nombre_Participants": true,
      "Demander_Noms_Participants": false,
      "Appliquer_Les_Taxes_Locales": true,
      "Note_Sur_Facture": "",
      "Calendrier_ICS_Liaison": "",
      "Calendrier_ICS_Liaison_2": "",
      "Calendrier_ICS_Liaison_3": "",
      "Taxe_Hebergement": null,
      "Rates_OTA": [],
      "DetailsComplementaires": {
        "details": {
          "134": {
            "ID": 134,
            "IDAttribut": 134,
            "Parametre": "Nombre d'adultes inclus",
            "Suffixe": "",
            "Icone": "user-alt",
            "Aide": "Le nombre d'adultes inclus dans le prix journalier. Si il n'y a pas de différence en le prix par adulte et enfant n'inscrivez rien dans les sections enfants et adultes.",
            "Choix": [],
            "Reponse": "2"
          }
        }
      }
    }
  },
  "request_id": "req_exemple"
}

Enveloppe de réponse

ChampType JSONDescription
success / errorbooleanRésultat de la requête API.
endpointstringservice
IDEntrepriseintegerCompte déduit de la clé API.
request_idstringIdentifiant de diagnostic, aussi présent dans X-Request-ID.
data.ExistebooleanIndique si la fonction de détail a trouvé la fiche.
data.Serviceobject | array videFiche si Existe=true; [] si Existe=false.

Champs de data.Service

Respectez la casse et les accents. Les champs conditionnels peuvent être absents. Une chaîne vide, null, [] et une clé absente ne sont pas interchangeables.

ChampType JSONDescription
IDServiceintegerIdentifiant du service.
Titrestring | nullTitre enregistré.
Categorie_TextestringChemin lisible de la catégorie.
IDCategoriestringIdentifiant préfixé C ou chaîne vide.
IDSousCategoriestringIdentifiant préfixé P ou chaîne vide.
IDSousSousCategoriestringIdentifiant préfixé S ou chaîne vide.
Descriptionstring | nullPeut contenir du HTML et des entités HTML. Assainir avant affichage.
QuantiténumberQuantité configurée, pas la disponibilité à une date donnée. La clé contient un accent.
TypeReservationintegerMode natif : 0 = séjour ou réservation sans multi-horaire; 1 = places par personne avec départs fixes; 2 = horaire lié à un inventaire. Un inventaire lié peut retourner -1 et ne se réserve pas directement.
EstHebergementbooleanClassement hébergement de la catégorie, distinct du mode de réservation.
TypeJoursintegerMode natif de durée (prop_typenuit), pas une durée. Pour un hébergement, 0 correspond aux nuitées; les autres modes dépendent du parcours.
PrixBasenumberPrix de base numérique, pouvant valoir 0. Ce n’est pas un devis pour les dates et participants.
SourcePrixBasestringProvenance du prix de base.
ReglePrixBasestringConsigne de lecture du prix de base.
ImagesarrayConditionnel : absent sans image. Chaque image contient IDPhoto (integer) et URL (string).
OuverturestringRésumé textuel des jours d’arrivée ou d’ouverture. Pas les créneaux ou disponibilités.
Tarificationarray<object> · conditionnelLignes avec type_tarification (slug stable), type_tarification_texte (libellé), Montant (number ou null) et SurDemande (boolean). duree_heures (number) pour les tarifs horaires. Voir la liste des types ci-dessous.
DatesOuverturesarray<object>Toujours présent; [] sans période précise. Chaque objet contient DateDebut et DateFin (strings YYYY-MM-DD). Aucune concaténation de dates.
PeriodeReservationGeneraleobject | nullFenêtre générale : DateDebut et DateFin (YYYY-MM-DD), ou null si non configurée. Distincte des périodes précises.
Reservation_en_lignestring« Activé » / « Désactivé » en français, pas un booléen.
Reservation_internestring« Activé » / « Désactivé » en français, pas un booléen.
Approbation_manuellestring« Activé » / « Désactivé » en français, pas un booléen.
Etatstring« Publié » / « Non visible » pour une fiche de service.
Nuit_MinimumintegerMinimum configuré. Nom historique : tenir compte du mode de durée.
Nuit_MaximumintegerMaximum configuré. 0 ne signifie pas que le service est indisponible.
Duree_Minimum_WEEK_ENDintegerMinimum configuré pour la fin de semaine.
Depot_En_Ligne_PourcentagenumberPourcentage, ex. 20 pour 20 %, pas un montant.
Depot_Local_PourcentagenumberPourcentage de dépôt configuré à l’interne.
Depot_En_Lignenumber | nullMontant numérique sans symbole. null si non renseigné; 0 si zéro. Les variantes de dépôt ne doivent pas être additionnées arbitrairement.
Depot_En_Ligne_Par_Nuitnumber | nullMontant numérique sans symbole. null si non renseigné; 0 si zéro. Les variantes de dépôt ne doivent pas être additionnées arbitrairement.
Depot_En_Ligne_Par_Semainenumber | nullMontant numérique sans symbole. null si non renseigné; 0 si zéro. Les variantes de dépôt ne doivent pas être additionnées arbitrairement.
Demander_Age_EnfantsbooleanDemande d’âge des enfants activée.
Demander_Nombre_ParticipantsbooleanDemande du nombre de participants activée.
Demander_Noms_ParticipantsbooleanDemande des noms activée.
Appliquer_Les_Taxes_LocalesbooleanActivation des taxes locales, sans leurs taux ni les montants du séjour.
Note_Sur_Facturestring | nullTexte configuré, éventuellement vide ou null.
Calendrier_ICS_LiaisonstringLien de calendrier configuré ou chaîne vide. Ne pas exposer inutilement les liens privés.
Calendrier_ICS_Liaison_2stringDeuxième lien de calendrier ou chaîne vide.
Calendrier_ICS_Liaison_3stringTroisième lien de calendrier ou chaîne vide.
Taxe_Hebergementnumber | nullTaux numérique sans symbole %, ex. 3.5 pour 3,5 %. null si non renseigné. Distinct du montant Montants.TaxeHebergement dans le devis.
Rates_OTAarrayPlans Booking/Expedia associés, ou []. Structure détaillée ci-dessous.
DetailsComplementairesobjectObjet contenant details, indexé par identifiant d’attribut. Structure ci-dessous.
Date_Ouverturestring · conditionnelAncien indicateur « Actif » sans fenêtre générale ni période précise; ce n’est pas une date.
IDInventaireinteger · conditionnelPrésent pour le mode horaire, même si la valeur configurée est 0.
ID_Service_Liaisoninteger · conditionnelPour les autres modes, présent si un service lié est configuré.

Attributs dynamiques : DetailsComplementaires.details

details est un objet indexé par identifiant, par exemple data.Service.DetailsComplementaires.details["134"]. Sans attribut, il vaut []. La liste varie selon la catégorie et la configuration.

ChampType JSONDescription
ID / IDAttributintegerIdentifiant de l’attribut; ID est conservé pour compatibilité.
Parametre / Suffixe / Icone / Aidestring | nullLibellé, unité, icône et aide; peuvent être vides.
Reponsestring | number | nullValeur de l’attribut. Les attributs monétaires (Suffixe=$) retournent un nombre ou null. Les autres réponses restent textuelles, par exemple « 2 » ou « Oui », selon l’attribut. Le suffixe est une métadonnée séparée du montant.
Choixarray<object>Options ou []. Chaque option contient ID (integer), Valeur et Icone (string ou null), Select (boolean). Seuls les choix avec Select=true sont sélectionnés.

InclureParametresVides=0 (défaut) retire les attributs sans réponse ni choix sélectionné. Avec 1, ils sont conservés sans inventer de valeur. Cette option ne force pas les autres champs conditionnels à apparaître. Un attribut à choix conservé contient aussi les options non sélectionnées.

Plans tarifaires : Rates_OTA[]

ChampType JSONDescription
IDRate / IDChambre_OTAstringIdentifiants externes.
Sourcestringbooking ou expedia.
Titre / TypeRatestringLibellé et type du plan tarifaire.
ModeCollecteinteger | nullnull pour Booking; code configuré pour Expedia, éventuellement null. Ce bloc ne fournit pas un prix de séjour.

Exemple de lecture en PHP

// $response = json_decode($body, true);
if (empty($response['success'])) {
    throw new RuntimeException($response['error_message'] ?? 'Erreur API');
}
if (empty($response['data']['Existe'])) {
    throw new RuntimeException('Fiche de service non disponible');
}
$service = $response['data']['Service'];
$prixBase = $service['PrixBase'];
$images = $service['Images'] ?? [];
$attributs = $service['DetailsComplementaires']['details'] ?? [];
$adultesInclus = $attributs[134]['Reponse'] ?? null;
foreach ($attributs as $attribut) {
    // Lire Reponse ou les Choix dont Select vaut true.
}

Erreurs et cas particuliers

ChampType JSONDescription
400 · request_errorerreurIDService absent ou non positif : « IDService est requis. »
404 · service_not_founderreurService inexistant, étranger au compte ou exclu par le contrôle d’accès.
200 · data.Existe=falsefiche absenteUn service autorisé peut être exclu par le filtre de date de fin de la fiche. data contient alors {"Existe":false,"Service":[]}.
401 / 429 / 500erreurAuthentification, débit ou erreur interne : voir les erreurs.
{
  "success": false,
  "error": true,
  "error_code": "service_not_found",
  "error_message": "Service introuvable.",
  "request_id": "req_exemple"
}

Pour calculer une réservation

Cette fiche ne fournit ni un devis complet ni une confirmation de disponibilité. Consulter les unités, les variations tarifaires, le calendrier puis la disponibilité détaillée pour les dates et participants. Ne pas additionner les alternatives de Tarification pour reconstruire le total du séjour.

Types tarifaires stables

type_tarification sert aux conditions dans votre code. type_tarification_texte sert uniquement à l’affichage et peut varier avec la langue. N’utilisez pas le libellé comme identifiant.

type_tarificationExemple de type_tarification_texteSens
par_nuitPrix par nuitTarif de nuitée.
par_jourPrix par jourTarif journalier.
a_partir_deÀ partir dePrix indicatif de départ, pas un devis.
prixPrixPrix général du service.
tarifTarifTarif générique, pouvant être gratuit ou sur demande.
saisonnierPrix saisonnierTarif saisonnier.
horaire2 heuresLa durée est séparée dans duree_heures, par exemple 2 ou 0.5.
autreLibellé non reconnuValeur de repli pour un type natif non encore répertorié; tolérer de nouveaux slugs.

Une gratuité retourne Montant=0 et SurDemande=false. Un tarif sur demande retourne Montant=null et SurDemande=true. Aucun montant ne contient de symbole monétaire.

Variations

GET/api/variationsLecture

Retourne les variations d’un service entre deux dates. Sur une courte plage, le résultat peut être détaillé jour par jour. Sur une plus grande plage, le résultat peut être regroupé par périodes homogènes.

Paramètres

NomTypeRequisDescription
IDServiceintOuiID du service.
DateDebutdateOuiDate de début.
DateFindateOuiDate de fin.
IDRatestringNonRate externe Booking/Expedia si applicable.
GET /api/variations?IDService=35197&DateDebut=2026-07-01&DateFin=2026-07-31
Authorization: Bearer VOTRE_CLE_API

Réponse HTTP 200 — aucune variation configurée

{
  "success": true,
  "error": false,
  "endpoint": "variations",
  "IDEntreprise": 9379,
  "data": {
    "mode": "detail",
    "IDService": 27644,
    "IDRate": "",
    "SourceCalendrier": "standard",
    "total_jours": 3,
    "total": 0,
    "variations": [],
    "CouvertureLecture": {
      "lecture_complete": true,
      "DateDebutDemandee": "2026-09-15",
      "DateFinDemandee": "2026-09-17",
      "jours_demandes": 3,
      "jours_avec_variation": 0,
      "jours_sans_variation": 3,
      "calendrier_entierement_vide": true,
      "periodes_sans_variation": [
        {
          "DateDebut": "2026-09-15",
          "DateFin": "2026-09-17",
          "Etat": "vide_aucune_variation_configuree"
        }
      ],
      "signification_absence": "La date a ete verifiee. Aucune ligne de variation tarifaire ou de disponibilite n est configuree; utiliser les valeurs par defaut du service. Ce n est pas une erreur ni une plage non retournee."
    }
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.modestringdetail jusqu’à 14 dates inclusives; resume au-delà.
data.IDService / IDRate / SourceCalendrierinteger / string / stringService, plan tarifaire optionnel et source standard, booking ou expedia.
data.total_joursintegerNombre de dates demandées, bornes incluses.
data.totalintegerNombre de lignes en mode detail; nombre de périodes en mode resume.
data.variationsarray<object> · mode detailUne ligne par date/configuration; [] si aucune variation.
data.periodesarray<object> · mode resumePériodes homogènes avec DateDebut, DateFin et params. Remplace variations.
data.total_lignesinteger · mode resumeNombre de lignes sources avant regroupement.
data.CouvertureLectureobjectlecture_complete, DateDebutDemandee, DateFinDemandee, jours_demandes, jours_avec_variation, jours_sans_variation, calendrier_entierement_vide, periodes_sans_variation et signification_absence.
CouvertureLecture.periodes_sans_variation[]objectDateDebut, DateFin et Etat=vide_aucune_variation_configuree.

Champs des variations et de params

ChampType JSONDescription
IDService / Dateinteger / stringEn mode detail seulement : service et date YYYY-MM-DD.
Variation_Quantite / Duree_Minimum_Arrivee / Jour_Arrivee / Duree_Minimum_Entre_ReservationsintegerValeurs natives de variation et de restrictions. Une variation de quantité n’est pas un nombre de places encore disponibles.
Arrivee_Interdite / Depart_Interdit / FermebooleanRestrictions de la date.
FraisGestionPourcentnumberPourcentage de frais configuré.
Prix / Duree_Minimum / Duree_Maximumnumber / integer / integerPour le mode séjour (TypeReservation=0).
IDHoraireinteger · conditionnelPour les autres modes, identifiant du créneau.
Prix_Adulte / Prix_Enfant / Prix_Etudiant / Prix_Aine / Prix_Petit_Enfant / Prix_Famillenumber · conditionnelTarifs par catégorie pour les activités/horaires; tarifs complémentaires aussi possibles en mode OTA séjour.
Prix_Grand_Enfantnumber · conditionnelSi disponible dans le schéma et pour les modes concernés.
IDRatestring · conditionnelPlan tarifaire en mode OTA.

Une période sans variation signifie que la lecture a bien couvert les dates et que les valeurs du service s’appliquent; elle n’est pas automatiquement fermée. La disponibilité détaillée reste l’autorité pour le prix réservable.

Emplacements

GET/api/emplacementsLecture

Retourne la liste des emplacements associés à un service. Possibilité d’inclure des dates pour obtenir une première lecture rapide de disponibilité par emplacement.

Paramètres

NomTypeDescription
IDServiceintService visé.
MotsClesarray|stringRecherche sur les emplacements.
DebutintOffset.
LimiteintNombre max.
DateDebutdateDate début pour lecture de disponibilité.
DateFindateDate fin.
IDReservationintRéservation à exclure dans une logique de modification.
GET /api/emplacements?IDService=35197&DateDebut=2026-07-10&DateFin=2026-07-15
Authorization: Bearer VOTRE_CLE_API

Filtres complémentaires

ChampType JSONDescription
AvecDescriptionbooleanDéfaut false. Avec 1, inclut Description dans les unités.
Nbr_Adulte / Nbr_Enfant / Nbr_ChienintegerDéfaut 0. Filtre les limites propres aux unités; ne remplace pas la validation du service ni des équipements.
DateDebut / DateFinstringFournir les deux dates ou aucune. DateFin doit être strictement postérieure à DateDebut; sinon HTTP 422.

Réponse HTTP 200 vérifiée — sans dates

{
  "success": true,
  "error": false,
  "endpoint": "emplacements",
  "IDEntreprise": 9379,
  "data": {
    "details": {
      "Total": 1,
      "TotalEmplacementsDisponibles": null,
      "Debut": 0,
      "Limite": 1
    },
    "services": [
      {
        "IDService": "27644",
        "TitreService": "Camping 1 service (eau)",
        "Categorie": "Camping Camping 1 service",
        "TypeService": "0",
        "Emplacements": [
          {
            "IDEmplacement": "8551",
            "Titre": "Frontenac # 01",
            "PlanX": "263",
            "PlanY": "903",
            "DateDebutValidite": "0000-00-00",
            "DateFinValidite": "0000-00-00",
            "EnLigne": true,
            "EstSaisonnier": false,
            "MinGrandeur": 0,
            "MaxGrandeur": 20,
            "MaxChien": -1,
            "MaxPerson": 0,
            "MaxAdulte": -1,
            "MaxEnfant": -1,
            "Menage": {
              "Statut": "inconnu",
              "Libelle": "Ménage non confirmé",
              "Pret": null,
              "TachesOuvertes": 0,
              "IDTaches": [],
              "DerniereCompletion": null
            }
          }
        ]
      }
    ]
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.details.TotalintegerNombre d’emplacements retournés sur la page, après filtrage daté si applicable. Ce n’est pas le total global du catalogue.
data.details.TotalEmplacementsDisponiblesinteger | nullNombre retourné avec dates; null sans dates.
data.details.Debut / LimiteintegerOffset et taille demandée; défaut 0 / 20, maximum 100. Le filtrage de disponibilité intervient après la sélection de la page SQL : une page courte ou vide ne prouve pas la fin des résultats.
data.servicesarray<object>Unités regroupées par service ou inventaire lié; [] si aucun groupe.
services[].IDService / TypeServicestringIdentifiants numériques historiques sous forme de chaînes.
services[].TitreService / Categoriestring | nullLibellés du service.
services[].UtiliseParIDServicearray<string> · conditionnelServices liés à un inventaire.
services[].Emplacementsarray<object>Unités de ce groupe; peut être vide après filtrage.
Emplacements[].IDEmplacementstringIdentifiant de l’unité.
Titre / Descriptionstring | nullDescription conditionnelle : AvecDescription=1.
PlanX / PlanYstring | nullCoordonnées natives sur le plan, désormais présentes aussi sans dates. Leur échelle dépend du fond de plan du service.
DateDebutValidite / DateFinValiditestringMM-DD si configuré, sinon « 0000-00-00 ». Ce ne sont pas des dates ISO complètes.
EnLigne / EstSaisonnierbooleanIndicateurs configurés. Avec dates, les unités saisonnières et les unités hors état normal sont exclues.
MinGrandeur / MaxGrandeur / MaxPerson / MaxAdulte / MaxEnfant / MaxChienintegerRestrictions configurées. Les sentinelles dépendent du champ : MaxPerson<=0 sans limite propre; MaxAdulte/MaxEnfant/MaxChien<0 sans limite propre, 0 n’autorise aucun participant de cette catégorie.
CodeBoiteClestring · conditionnelCode privé de boîte à clés, si configuré. Ne pas l’afficher dans un catalogue public.
IDUtilisateurinteger | string · conditionnelUtilisateur assigné à l’unité.
MenageobjectStatut, Libelle, Pret (boolean ou null), TachesOuvertes (integer), IDTaches (array), DerniereCompletion (string ou null). Voir l’état de ménage.

Avec dates, seules les unités sans chevauchement d’affectation sont retournées. Pour les capacités globales, les équipements et le tarif, utiliser /api/disponibilite. Le ménage ne bloque pas commercialement les réservations futures.

Calendrier rapide

GET/api/calendrierLecture rapide

Endpoint recommandé pour permettre à un partenaire de construire rapidement un calendrier de disponibilité sur les 30 prochains jours. Cet endpoint peut utiliser une fonction interne très rapide qui retourne les jours non disponibles d’un service, et optionnellement d’un emplacement précis via IDEmplacement.

Cas d’usage : Le partenaire peut scanner les services et emplacements, puis charger les 30 prochains jours pour bâtir une grille de calendrier sans appeler la disponibilité détaillée pour chaque date.

Paramètres

NomTypeRequisDescription
IDServiceintOuiID du service.
DateDebutdateNonDéfaut suggéré : aujourd’hui.
DateFindateNonDéfaut suggéré : 30 jours après DateDebut.
IDEmplacementintNonPermet de cibler un emplacement précis.

Réponse HTTP 200 vérifiée

{
  "success": true,
  "error": false,
  "endpoint": "calendrier",
  "IDEntreprise": 9379,
  "data": {
    "success": true,
    "IDService": 27644,
    "IDEmplacement": 0,
    "jours": [
      {
        "date": "2026-09-15",
        "disponible": true
      },
      {
        "date": "2026-09-16",
        "disponible": true
      },
      {
        "date": "2026-09-17",
        "disponible": true
      }
    ]
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.successbooleanRésultat du calcul rapide.
data.IDService / data.IDEmplacementintegerService et emplacement demandés; IDEmplacement=0 signifie aucun emplacement précis.
data.joursarray<object>Un élément pour chaque date, bornes incluses.
data.jours[].datestringDate YYYY-MM-DD, clé en minuscules.
data.jours[].disponiblebooleanPremière indication de disponibilité, sans devis ni garantie pour un groupe ou un séjour complet.

Les anciennes clés suggérées Jours, JoursComplets, Date et Disponible ne font pas partie de ce retour. Les valeurs par défaut sont aujourd’hui et DateDebut + 30 jours (31 dates avec les deux bornes). L’écart maximal entre les dates est de 62 jours. Valider le séjour complet via la disponibilité détaillée.

Disponibilité détaillée

POST/api/disponibiliteValidation précise

Vérifie la disponibilité et calcule le prix d’un séjour ou d’une activité précise. Peut recevoir un IDEmplacement dans Details.

Utiliser cet endpoint pour valider un choix précis. Pour construire un calendrier de 30 jours, privilégier /api/calendrier.

Corps JSON

{
  "IDService": 35197,
  "Details": {
    "Date_Debut": "2026-07-10",
    "Date_Fin": "2026-07-15",
    "Nbr_Adulte": 2,
    "Nbr_Enfant": 1,
    "Nbr_Etudiant": 0,
    "Nbr_Aine": 0,
    "Nbr_PetitEnfant": 0,
    "Nbr_GrandEnfant": 0,
    "IDEmplacement": 8832,
    "HeureDebut": 0,
    "HeureDuree": 0
  }
}

Réponse HTTP 200 vérifiée

Exemple Démo Camping pour le 15 au 17 septembre 2026, avec Nbr_Adulte=2. Le calcul ne crée pas de réservation.

{
  "success": true,
  "error": false,
  "endpoint": "disponibilite",
  "IDEntreprise": 9379,
  "data": {
    "IDService": 27644,
    "TypeReservation": "0",
    "Disponible": true,
    "NbrDisponible": 17,
    "SousTotal": 76,
    "Frais": 3.5,
    "Total": 91.41,
    "Montants": {
      "SousTotal": 76,
      "Frais": 3.5,
      "Taxe1": 3.975,
      "Taxe2": 7.93,
      "TaxeHebergement": 0,
      "Rabais": 0,
      "Depot": 18.28,
      "DepotSecurite": 0,
      "Total": 91.41
    },
    "Avertissement": "",
    "DisponibiliteParJour": 17,
    "Erreur": ""
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.IDServiceintegerService évalué.
data.TypeReservationstring · conditionnelMode natif retourné par la base, ex. « 0 ». Peut être absent si la fiche est introuvable dans le moteur.
data.Disponiblebooleantrue uniquement si le moteur indique une disponibilité et aucune erreur métier. Un dépassement de capacité retourne false même s’il reste des unités.
data.NbrDisponiblenumber | nullQuantité restante selon le mode, si fournie par le moteur.
data.SousTotal / Frais / Totalnumber | nullMontants numériques sans symbole. Le bloc Montants complète ces valeurs avec les taxes, rabais et dépôts.
data.Montantsobject · conditionnelBloc numérique ajouté en bêta; absent si le service n’est pas trouvé par le moteur.
data.Montants.SousTotal / Frais / Taxe1 / Taxe2 / TaxeHebergement / Rabais / Depot / DepotSecurite / Totalnumber | nullValeurs directement issues du moteur. Taxe1, Taxe2 et TaxeHebergement sont des montants, jamais des taux. null signifie valeur non fournie, pas zéro.
data.Avertissement / ErreurstringMessages métier, éventuellement vides; plusieurs messages peuvent être séparés par |.
data.DisponibiliteParJournumber | nullMalgré son nom historique, le retour actuel est une quantité synthétique, pas une liste de dates. Utiliser /api/calendrier pour une grille.

Conserver le total calculé par le moteur. Les taxes peuvent garder une précision intermédiaire (ex. 3.975); ne pas reconstruire le total à partir de montants arrondis séparément. Les rabais et dépôts ne sont pas des montants à ajouter au total. La disponibilité peut changer avant la création du panier.

Paramètres de Details

ChampType JSONDescription
Date_Debut / Date_FinstringDates YYYY-MM-DD. Date_Debut requise; Date_Fin prend Date_Debut si omise. Le mode de réservation détermine si une même journée est valide. Écart maximal : 62 jours.
Nbr_Adulte / Nbr_Enfant / Nbr_Etudiant / Nbr_Aine / Nbr_PetitEnfant / Nbr_GrandEnfantintegerNombres de participants par catégorie native. Utiliser ces noms exacts; Nombre_Adultes n’est pas l’alias de Nbr_Adulte.
IDEmplacement / IDHoraireintegerUnité ou créneau correspondant au service, selon le parcours.
Nbr_Chien / Nbr_Vehicule / Nbr_VehiculeElectriqueintegerQuantités supplémentaires prises en compte selon la configuration.
CodePromo / CodeMembrestringCode promotionnel ou membre, selon les règles du commerce.
IDReservationinteger · conditionnelPour évaluer une modification; fournir aussi IDSession au niveau racine. La réservation doit appartenir à la session et au compte.

Réservation

GET POST /api/reservation Lecture + écriture

Endpoint principal permettant soit de consulter une réservation ou un panier de session en GET, soit d’ajouter ou modifier les éléments du panier en POST. La transmission du client et le passage au paiement se font exclusivement avec POST /api/checkout.

GET — Consulter une réservation ou un panier

Retourne soit le panier complet d’une session, soit une réservation précise appartenant à cette session. Cet endpoint ne dépend pas de $_SESSION['idusr'] : l’entreprise est déterminée automatiquement à partir de la clé API.

Paramètres

Paramètre Type Obligatoire Description
IDSession string Oui Identifiant de session utilisé pour le panier ou la réservation : 16 à 44 lettres, chiffres, tirets ou soulignements.
IDReservation integer Non Si fourni, retourne uniquement cette réservation. Sinon, retourne tout le panier de la session.

Exemple — panier complet

GET /api/reservation?IDSession=campingqc_123abc
Authorization: Bearer VOTRE_CLE_API

Exemple — réservation précise

GET /api/reservation?IDSession=campingqc_123abc&IDReservation=2786491
Authorization: Bearer VOTRE_CLE_API

Exemple de réponse — panier

{
  "success": true,
  "error": false,
  "endpoint": "reservation",
  "IDEntreprise": 123,
  "data": {
    "success": true,
    "error": false,
    "details": {
      "IDSession": "campingqc_123abc",
      "TotalReservations": 2,
      "SousTotalPanier": 540,
      "TotalPanier": 620.87
    },
    "Reservations": [
      {
        "IDReservation": 2786491,
        "IDService": 35197,
        "TitreService": "Terrain 3 services",
        "Reservation_Date_Debut": "2026-07-10",
        "Reservation_Date_Fin": "2026-07-15",
        "Nombre_Adultes": 2,
        "Nombre_Enfants": 1,
        "Quantite": 1,
        "Status": "Panier",
        "SousTotal": 270,
        "Total": 310.44,
        "Emplacements": [
          {
            "IDEmplacement": 8832,
            "TitreEmplacement": "Terrain A-12",
            "DateDebut": "2026-07-10",
            "DateFin": "2026-07-15"
          }
        ],
        "Elements_Associes": []
      }
    ]
  },
  "request_id": "req_exemple"
}

POST — Gérer une réservation

Le champ action accepte uniquement ajouter ou modifier. Une confirmation doit passer par le checkout; l’annulation ne fait pas partie de ce contrôleur partenaire.

Pour une modification, IDReservation doit appartenir au compte authentifié et à IDSession. IDService peut être omis pour conserver le service courant; s’il est fourni, il doit appartenir au même compte. Un IDEmplacement doit appartenir à ce service. Toute référence étrangère est retournée comme introuvable.

Actions supportées

Action Description
ajouter Ajoute une ou plusieurs réservations dans une session.
modifier Modifie une réservation existante via IDReservation.
Migration : action=confirmer est retirée et retourne 410 confirmation_endpoint_retired. N’envoyez pas action=annuler; utilisez le mécanisme de gestion approprié hors de ce parcours partenaire.

Exemple — ajouter

{
  "action": "ajouter",
  "IDSession": "campingqc_123abc",
  "reservations": [
    {
      "IDService": 35197,
      "IDEmplacement": 8832,
      "Date_Debut": "2026-07-10",
      "Date_Fin": "2026-07-15",
      "Nbr_Adulte": 2,
      "Nbr_Enfant": 1
    }
  ]
}

Exemple — modifier

{
  "action": "modifier",
  "IDSession": "campingqc_123abc",
  "reservations": [
    {
      "IDReservation": 2786491,
      "IDService": 35197,
      "IDEmplacement": 8832,
      "Date_Debut": "2026-07-11",
      "Date_Fin": "2026-07-16",
      "Nbr_Adulte": 2,
      "Nbr_Enfant": 1
    }
  ]
}

Checkout partenaire

POST /api/checkout Création et paiement

Crée une photographie sécurisée du panier, associe le client aux réservations et retourne l’URL de paiement hébergée. Les montants sont recalculés par RéservPro; le partenaire ne transmet aucun montant à débiter.

Idempotence obligatoire : fournir un en-tête Idempotency-Key unique d’au moins 8 caractères pour chaque nouveau checkout. En cas de délai réseau, répéter exactement la même requête avec la même clé. Ne jamais réutiliser cette clé pour un autre panier ou un autre client.

En-têtes

Authorization: Bearer VOTRE_CLE_API
Content-Type: application/json
Accept: application/json
Idempotency-Key: cq-commande-20260710-000123

Corps JSON

ChampTypeRequisDescription
IDSessionstringOuiSession du panier préalablement construit avec /api/reservation.
customerobjectOuiCoordonnées complètes du client; voir le tableau suivant.
iframe_originstringOuiOrigine exacte qui intégrera l’iframe, par exemple https://reservation.partenaire.ca. Ne pas inclure de chemin.
webhook_urlstringRecommandéURL HTTPS publique sur le port 443 qui recevra les changements d’état. Les identifiants dans l’URL, les redirections et les adresses privées ou réservées sont refusés.
webhook_secretstringNonSecret de signature de 24 à 512 caractères. S’il est omis avec une URL webhook, RéservPro en génère un dans la réponse de création ou de reprise idempotente; il n’est jamais publié par GET.
partner_referencestringNonRéférence stable du partenaire, utile pour le rapprochement; maximum 191 caractères.
metadataobjectNonDonnées métier non sensibles, maximum 16 Kio. Ne jamais y placer de donnée de carte.
expires_inintegerNonDurée de validité en secondes, de 300 à 86 400; défaut : 1 800 secondes.

Objet customer

ChampRequisDescription
first_name, last_nameOuiPrénom (50 caractères) et nom (75 caractères).
email, phoneOuiCourriel valide (100 caractères) et téléphone (20 caractères).
companyNonEntreprise du client, maximum 75 caractères.
phone2, faxNonSecond téléphone et télécopieur, maximum 20 caractères chacun.
address1, city, state, country, postal_codeOuiAdresse de facturation ou de réservation. Limites respectives : 200, 50, 12, 50 et 12 caractères; utiliser un code court comme QC pour state.
address2NonComplément d’adresse, maximum 100 caractères.
languageNonfr ou en; défaut fr.
client_idNonIdentifiant d’un client qui appartient déjà au compte marchand.
driver_license, driver_license_expiry, arrival_timeNonInformations complémentaires lorsque requises par l’établissement; limites : 25, 10 et 10 caractères.
communication, sms_communicationNonPréférences de communication. Valeurs acceptées : -2, 0 ou 1; défaut 0.
client_typeNonType de client sous forme d’entier positif, maximum 8 388 607.
referenceNonRéférence numérique, de 0 à 32 767.
noteNonNote interne associée au client, maximum 4 000 caractères.

Une valeur qui dépasse sa limite est refusée avec HTTP 422 invalid_checkout; elle n’est jamais tronquée silencieusement.

Confidentialité : RéservPro conserve ces coordonnées dans le snapshot privé du checkout afin de finaliser le dossier client. Elles ne sont jamais incluses dans la réponse de statut ni dans un webhook. Ne placez aucune donnée client dans metadata.

Exemple cURL — créer le checkout

curl -X POST 'https://beta.reservpro.com/api/checkout' \
  -H 'Authorization: Bearer VOTRE_CLE_API' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Idempotency-Key: cq-commande-20260710-000123' \
  --data '{
    "IDSession": "campingqc_123abc",
    "customer": {
      "first_name": "Hugo",
      "last_name": "Girard",
      "email": "hugo@example.com",
      "phone": "514-555-0199",
      "address1": "123 rue Exemple",
      "address2": "",
      "city": "Montréal",
      "state": "QC",
      "country": "Canada",
      "postal_code": "H1H 1H1",
      "language": "fr"
    },
    "iframe_origin": "https://reservation.partenaire.ca",
    "webhook_url": "https://reservation.partenaire.ca/webhooks/reservpro",
    "webhook_secret": "whsec_EXEMPLE_A_REMPLACER_32_CARACTERES",
    "partner_reference": "CQ-2026-000123",
    "metadata": {
      "channel": "camping-quebec"
    }
  }'

Réponse de création

{
  "success": true,
  "error": false,
  "endpoint": "checkout",
  "request_id": "req_…",
  "checkout": {
    "id": "chk_…",
    "partner_reference": "CQ-2026-000123",
    "metadata": {
      "channel": "camping-quebec"
    },
    "status": "payment_pending",
    "status_url": "https://beta.reservpro.com/api/checkout?IDCheckout=chk_…",
    "version": 1,
    "reservation_ids": [
      2786491
    ],
    "invoice_ids": [],
    "invoices": [],
    "item_count": 1,
    "amount_total": 310.44,
    "amount_due": 155.22,
    "amount_paid": 0,
    "balance_due": 155.22,
    "currency": "CAD",
    "payment_required": true,
    "payment_completed": false,
    "payment_url": "https://beta.reservpro.com/api/payment/rpt_…",
    "iframe_html": "<iframe src=\"https://beta.reservpro.com/api/payment/rpt_…\" …></iframe>",
    "iframe_origin": "https://reservation.partenaire.ca",
    "payment_origin": "https://reservpro.com",
    "payment_gateway": "stripe",
    "expires_at": "2026-07-10T15:00:00-04:00",
    "paid_at": null,
    "completed_at": null,
    "released_at": null,
    "created_at": "2026-07-10T14:30:00-04:00",
    "updated_at": "2026-07-10T14:30:00-04:00",
    "checkout_token": "rpt_…",
    "idempotent_replay": false
  }
}

Une création retourne HTTP 201; une reprise idempotente retourne 200 avec idempotent_replay: true. status_url exige toujours l’authentification Bearer. checkout_token est la capacité temporaire déjà intégrée à payment_url; ne la transmettez jamais ailleurs. Si RéservPro génère webhook_secret, il apparaît dans la création et ses reprises idempotentes, mais jamais dans un GET. Stockez-le immédiatement dans un gestionnaire de secrets.

GET — consulter l’état

GET /api/checkout?IDCheckout=chk_… État autoritaire
curl --get 'https://beta.reservpro.com/api/checkout' \
  -H 'Authorization: Bearer VOTRE_CLE_API' \
  -H 'Accept: application/json' \
  --data-urlencode 'IDCheckout=chk_…'

La réponse place l’état dans checkout et reprend les montants, références et dates. Pour ne pas republier le jeton de paiement, payment_url et iframe_html valent null lors d’un GET. Conservez la réponse de création; si elle est perdue après un délai réseau, répétez le même POST avec la même clé d’idempotence. Une ressource d’un autre compte marchand retourne une réponse introuvable.

États possibles

ÉtatTerminalSignification
payment_pendingNonLe checkout attend un paiement dans l’interface hébergée.
confirmation_pendingNonAucun paiement n’est requis, mais le client doit encore confirmer dans l’interface hébergée afin de finaliser la réservation et sa facture.
paidOuiLe paiement a été validé et enregistré par RéservPro.
completedOuiLa confirmation sans paiement a été finalisée et la facture a été créée.
failedRéservéÉtat prévu pour une évolution future; il n’est pas produit par le parcours actuel.
expiredOuiLe délai est dépassé et aucun nouveau paiement ne peut être commencé. Un retour fournisseur déjà engagé peut encore être rapproché pendant la grâce interne; le statut autoritaire peut alors devenir paid.
cancelledOuiLes réservations du checkout ne sont plus actives.

Après expiration, RéservPro conserve le snapshot pendant une grâce de 15 minutes par défaut afin de rapprocher un paiement déjà engagé. Sans preuve de paiement, le worker restaure ensuite atomiquement les réservations dans le IDSession partenaire et renseigne released_at. Pour reprendre les mêmes éléments, attendez que released_at ne soit plus null, puis créez un checkout avec une nouvelle clé d’idempotence. L’événement de restauration utilise checkout.updated.

Considérez uniquement le statut retourné par GET /api/checkout ou par un webhook RéservPro validé. Ne concluez jamais qu’un paiement est réussi à partir d’une redirection du navigateur.

Iframe de paiement

Le champ iframe_html contient une iframe prête à intégrer. payment_url peut aussi être utilisé comme attribut src ou ouvert dans une page dédiée. Cette URL contient une capacité temporaire : ne la journalisez pas, ne la modifiez pas et ne la partagez pas.

  • iframe_origin doit être l’origine HTTPS exacte de la page parente : schéma, hôte et port, sans chemin, query string ni fragment.
  • La page de paiement applique une politique CSP frame-ancestors limitée à cette origine. Une intégration depuis une autre origine est refusée par le navigateur.
  • La clé API Bearer reste sur le serveur partenaire et n’est jamais transmise à l’iframe.
  • Les messages postMessage, lorsqu’ils sont utilisés, servent uniquement à mettre à jour l’interface. Le parent doit valider event.origin, event.source et la structure du message.
  • Un message navigateur, une fermeture d’iframe ou une URL de retour ne constitue jamais une preuve de paiement. Après tout signal UX, interroger GET /api/checkout.

Message de mise à jour de l’iframe

{
  "type": "reservpro.checkout.status",
  "checkout_id": "chk_…",
  "status": "paid",
  "payment_completed": true
}

Le message est envoyé uniquement à iframe_origin. Dans la page parente, conserver une référence vers l’élément iframe et accepter le message seulement si event.origin correspond exactement à payment_origin, si event.source === iframe.contentWindow, si checkout_id est celui attendu et si le schéma ci-dessus est valide. Le serveur partenaire doit ensuite confirmer l’état avec le GET authentifié; le navigateur ne doit jamais appeler l’API avec la clé Bearer.

Webhooks de checkout

Lorsqu’un webhook_url est fourni à la création, RéservPro envoie les événements de checkout par POST JSON. Les types actuels comprennent checkout.created — dont le checkout peut être payment_pending ou confirmation_pending — puis checkout.paid, checkout.completed, checkout.expired, checkout.cancelled et, lors d’une autre évolution matérielle, checkout.updated. L’état et l’événement failed sont réservés à une évolution future.

En-têtes de livraison

Content-Type: application/json
X-ReservPro-Event: checkout.paid
X-ReservPro-Event-ID: evt_…
X-ReservPro-Timestamp: 1783711800
X-ReservPro-Signature: v1=SIGNATURE_HEXADECIMALE

Corps type

{
  "id": "evt_…",
  "type": "checkout.paid",
  "created_at": "2026-07-10T18:10:00Z",
  "data": {
    "checkout": {
      "id": "chk_…",
      "partner_reference": "CQ-2026-000123",
      "status": "paid",
      "version": 2,
      "amount_due": 155.22,
      "amount_paid": 155.22,
      "balance_due": 0,
      "currency": "CAD"
    }
  },
  "context": {
    "previous_status": "payment_pending"
  }
}

Validation de la signature

La signature est calculée sur les octets exacts du corps reçu : HMAC_SHA256(timestamp + "." + raw_body, webhook_secret). Comparez v1=… en temps constant, refusez les timestamps trop anciens et ne recomposez jamais le JSON avant la validation.

$rawBody = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_RESERVPRO_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_RESERVPRO_SIGNATURE'] ?? '';
$eventId = $_SERVER['HTTP_X_RESERVPRO_EVENT_ID'] ?? '';
$secret = getenv('RESERVPRO_WEBHOOK_SECRET');

if (!is_string($secret) || $secret === '' || !preg_match('/^\d{10}$/D', $timestamp)) {
    http_response_code(401);
    exit;
}

if (abs(time() - (int) $timestamp) > 300) {
    http_response_code(401);
    exit;
}

$expected = 'v1=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit;
}

$event = json_decode($rawBody, true, 64, JSON_THROW_ON_ERROR);
if (!is_array($event) || !preg_match('/^evt_[A-Za-z0-9_-]+$/D', $eventId)
    || ($event['id'] ?? '') !== $eventId) {
    http_response_code(400);
    exit;
}
// Enregistrer $eventId avec une contrainte UNIQUE avant le traitement métier.
// Si $eventId existe déjà, répondre 2xx sans retraiter l’événement.
http_response_code(204);
Contrat de livraison : livraison au moins une fois, jusqu’à 10 tentatives. Le délai croît de 30 secondes jusqu’à un maximum de 6 heures, avec une légère variation aléatoire. Un même X-ReservPro-Event-ID peut donc être reçu plusieurs fois. Persistez l’événement, dédupliquez-le, répondez rapidement avec un code 2xx et traitez le métier de façon idempotente.
Ordre et secours : ne supposez pas que les événements arrivent dans l’ordre. Utilisez data.checkout.version et confirmez toujours l’état courant avec GET /api/checkout?IDCheckout=…. Le polling demeure le mécanisme de secours lorsqu’un webhook tarde ou échoue.

Validation d’accès

POST /api/gate-access Contrôle d’accès

Endpoint permettant de valider un code d’accès pour autoriser ou refuser un passage. Le code peut être lié à un accès saisonnier ou à une réservation active.

Important : la logique de validation est entièrement gérée par RéservPro. Le partenaire doit seulement transmettre le code à valider. Lorsque l’accès est reconnu, la réponse peut inclure les informations du client, du site et du véhicule associé au badge.

Paramètres

Nom Type Requis Description
code string Oui Code d’accès à valider.
type integer Non Type de validation. 0 = entrée, 1 = sortie. Défaut : 0.
save_log boolean Non Indique si la validation doit être enregistrée dans RéservPro. Défaut : true.

Exemple — POST JSON

{
  "code": "ABC123",
  "type": 0,
  "save_log": true
}

Réponse — accès saisonnier autorisé

{
  "success": true,
  "error": false,
  "endpoint": "gate-access",
  "IDEntreprise": 123,
  "data": {
    "valid": true,
    "type": "saisonnier",
    "message": "Accès saisonnier valide.",
    "access": {
      "code_access": "ABC123",
      "validation_type": "entree",
      "id_validation": 456
    },
    "saisonnier": {
      "saison_id": 987,
      "saison_datedebut": "2026-05-01",
      "saison_datefin": "2026-10-15"
    },
    "site": {
      "IDEmplacement": 8832,
      "Nom": "Terrain A-12"
    },
    "client": {
      "usr_id": 789,
      "nom": "Jean Tremblay",
      "email": "jean@example.com"
    },
    "vehicule": {
      "vps_id": 321,
      "type": "Automobile",
      "marque": "Toyota",
      "model": "RAV4",
      "couleur": "Noir",
      "annee": "2020",
      "plaque": "ABC123",
      "no_serie": "",
      "vignette": 1,
      "no_acces": "ABC123",
      "conducteur": "Marie Tremblay",
      "informations": ""
    }
  },
  "request_id": "req_exemple"
}

Réponse — accès réservation autorisé

{
  "success": true,
  "error": false,
  "endpoint": "gate-access",
  "IDEntreprise": 123,
  "data": {
    "valid": true,
    "type": "reservation",
    "message": "Accès réservation valide.",
    "access": {
      "code_access": "XYZ789",
      "validation_type": "entree",
      "id_validation": 457
    },
    "reservation": {
      "reserv_id": 2786491,
      "reserv_datedebut": "2026-07-10",
      "reserv_datefin": "2026-07-15",
      "reserv_actif": 1,
      "reserv_inv": 1433936
    },
    "gate_data": {
      "id": 55,
      "modified": 0
    }
  },
  "request_id": "req_exemple"
}

Réponse — accès refusé

{
  "success": true,
  "error": false,
  "endpoint": "gate-access",
  "IDEntreprise": 123,
  "data": {
    "valid": false,
    "type": "",
    "message": "Accès refusé : aucun saisonnier ou réservation active trouvé pour ce code.",
    "access": {
      "code_access": "ABC123",
      "validation_type": "entree"
    }
  },
  "request_id": "req_exemple"
}

Champs de réponse

Champ Type Description
valid boolean Indique si le code donne accès ou non.
type string Type d’accès reconnu. Valeurs possibles : saisonnier ou reservation.
site object Emplacement associé. Pour un saisonnier, provient de vit_pac_saisonnier.saison_idplan. Pour une réservation, peut être obtenu via l’assignation d’emplacement.
vehicule object Informations du véhicule lorsque le code correspond à une carte d’accès véhicule : type, marque, modèle, couleur, année, plaque et conducteur.
client object Client lié au badge ou à la réservation.

Exemple PHP / cURL

$payload = [
    'code' => 'ABC123',
    'type' => 0,
    'save_log' => true
];

$ch = curl_init('https://beta.reservpro.com/api/gate-access');

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_HTTPHEADER => [
        'Accept: application/json',
        'Authorization: Bearer VOTRE_CLE_API',
        'Content-Type: application/json'
    ],
    CURLOPT_TIMEOUT => 30
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);

if (!empty($data['data']['valid'])) {
    echo 'Accès autorisé';
} else {
    echo 'Accès refusé';
}

Informations et historique ajoutés en bêta

La réponse conserve ses champs existants et ajoute sites (toutes les affectations d’une réservation), validite, FuseauHoraire et Historique : les cinq passages précédant la validation courante. HistoriqueAvantValidation=true précise ce moment. save_log=false vérifie sans enregistrer de passage.

La validité native est vérifiée par jour, avec bornes inclusives. Les dates ne représentent pas des heures d’ouverture précises. Les réservations annulées sont refusées. Voir la fiche de l’historique pour les anciens logs incomplets.

Liste des codes d’accès

GET /api/gate-codes Contrôle d’accès

Endpoint permettant d’obtenir la liste des codes d’accès assignés aux réservations. Il peut être utilisé par un système de contrôle d’accès pour synchroniser ou consulter les accès actifs sur une période donnée.

Important : l’entreprise est automatiquement déterminée à partir de la clé API. Le partenaire ne doit pas transmettre d’identifiant d’entreprise.
Nouveaux champs : la réponse peut maintenant inclure le site assigné à la réservation, ainsi que les informations du véhicule lorsque le code correspond à une carte d’accès véhicule.

Paramètres

Nom Type Requis Description
DateDebut date Non Date de début du filtre. Format recommandé : YYYY-MM-DD.
DateFin date Non Date de fin du filtre. Format recommandé : YYYY-MM-DD.
IDReservation integer Non Permet de retourner les codes d’une réservation précise.
code string Non Permet de rechercher un code précis.
Debut integer Non Position de départ pour la pagination. Défaut : 0.
Limite integer Non Nombre maximum de résultats retournés. Défaut et maximum : 100.

Filtre par date

Lorsque DateDebut et/ou DateFin sont fournis, l’API retourne les codes liés aux réservations qui chevauchent la période demandée.

Par exemple, une réservation du 2026-07-01 au 2026-07-10 sera retournée pour une recherche du 2026-07-05 au 2026-07-06.

Source des informations supplémentaires

Information Source RéservPro Détail
Service vit_pac Le service est retourné dans service.IDService et service.Titre.
Site d’une réservation vit_pac_plan_reserv + vit_pac_plan pr_reserv_id pointe vers la réservation et pr_plan_no pointe vers plan_no.
Site d’un saisonnier vit_pac_saisonnier + vit_pac_plan saison_idplan pointe vers vit_pac_plan.plan_no.
Véhicule vit_pac_users_veh Retourne modèle, couleur, plaque, type, année, vignette et carte d’accès.
Conducteur vit_pac_client_membre vps_conducteur pointe vers vpm_id, et le nom est dans vpm_nom.

Exemple

GET /api/gate-codes?DateDebut=2026-07-01&DateFin=2026-07-31
Authorization: Bearer VOTRE_CLE_API

Exemple avec pagination

GET /api/gate-codes?DateDebut=2026-07-01&DateFin=2026-07-31&Debut=0&Limite=100
Authorization: Bearer VOTRE_CLE_API

Réponse type

{
  "success": true,
  "error": false,
  "endpoint": "gate-codes",
  "IDEntreprise": 123,
  "data": {
    "success": true,
    "error": false,
    "details": {
      "Total": 2,
      "Debut": 0,
      "Limite": 100,
      "DateDebut": "2026-07-01",
      "DateFin": "2026-07-31"
    },
    "codes": [
      {
        "code": "ABC123",
        "type": "reservation",
        "reservation": {
          "IDReservation": 2786491,
          "DateDebut": "2026-07-10",
          "DateFin": "2026-07-15",
          "Statut": 1,
          "Arrivee": -1,
          "IDFacture": 1433936
        },
        "service": {
          "IDService": 35197,
          "Titre": "Terrain 3 services"
        },
        "site": {
          "IDEmplacement": 8832,
          "Nom": "Terrain A-12"
        },
        "client": {
          "IDClient": 789,
          "Nom": "Jean Tremblay",
          "Email": "jean@example.com",
          "Telephone": "514-555-1234"
        },
        "vehicule": {
          "IDVehicule": 321,
          "Type": "Automobile",
          "Marque": "Toyota",
          "Modele": "RAV4",
          "Couleur": "Noir",
          "Annee": "2020",
          "Plaque": "ABC123",
          "NoSerie": "",
          "Vignette": 1,
          "CarteAcces": "ABC123",
          "Conducteur": "Marie Tremblay",
          "Informations": ""
        },
        "meta": {
          "DateCreation": "2026-07-10 14:32:00",
          "DateModification": null,
          "Modifie": 0
        }
      }
    ]
  },
  "request_id": "req_exemple"
}

Comportement lorsque le véhicule est absent

Si le code d’accès est lié à une réservation, mais qu’aucun véhicule ne correspond à ce code, le bloc vehicule est retourné avec des valeurs vides. L’API ne choisit pas automatiquement un véhicule du client afin d’éviter toute ambiguïté.

"vehicule": {
  "IDVehicule": 0,
  "Type": "Automobile",
  "Marque": "",
  "Modele": "",
  "Couleur": "",
  "Annee": "",
  "Plaque": "",
  "NoSerie": "",
  "Vignette": 0,
  "CarteAcces": "",
  "Conducteur": "",
  "Informations": ""
}

Exemple PHP / cURL

$params = [
    'DateDebut' => '2026-07-01',
    'DateFin' => '2026-07-31',
    'Debut' => 0,
    'Limite' => 100
];

$url = 'https://beta.reservpro.com/api/gate-codes?' . http_build_query($params);

$ch = curl_init($url);

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Accept: application/json',
        'Authorization: Bearer VOTRE_CLE_API'
    ],
    CURLOPT_TIMEOUT => 30
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);

if (!empty($data['data']['codes'])) {
    foreach ($data['data']['codes'] as $row) {
        $site = isset($row['site']['Nom']) ? $row['site']['Nom'] : '';
        $plaque = isset($row['vehicule']['Plaque']) ? $row['vehicule']['Plaque'] : '';

        echo $row['code'] . ' - ' .
             $row['reservation']['DateDebut'] . ' - ' .
             $site . ' - ' .
             $plaque . PHP_EOL;
    }
}

Informations ajoutées en bêta

Chaque code de réservation inclut sites et Historique. Le bloc site existant reste présent pour compatibilité; sites couvre les réservations avec plusieurs affectations. L’historique contient les cinq derniers passages enregistrés du code pour cette entreprise. Voir les limites des anciens journaux.

Historique d’un code d’accès

GET/api/gate-historyBêta

Consulter les passages d’un code, y compris après son expiration ou sa désactivation.

Paramètres

ParamètreRègle
codeRequis. Code exact, 160 octets maximum.
Limite5 passages par défaut; maximum 100.

Exemple

GET /api/gate-history?code=CODE_EXEMPLE&Limite=5
Authorization: Bearer VOTRE_CLE_BETA

Réponse

data.Historique contient IDValidation, Date, Type (entree/sortie), IDReservation ou IDSaisonnier. Ordre décroissant par date et identifiant.

{
  "success": true,
  "error": false,
  "endpoint": "gate-history",
  "IDEntreprise": 123,
  "data": {
    "code": "CODE_EXEMPLE",
    "FuseauHoraire": "America/Montreal",
    "Historique": [
      {
        "IDValidation": 789,
        "Date": "2026-09-08 11:30:00",
        "Type": "sortie",
        "IDReservation": 456,
        "IDSaisonnier": null
      }
    ]
  },
  "request_id": "req_exemple"
}

Limites de l’historique

Seuls les passages dont le code et l’entreprise ont été enregistrés sont retournés. Les anciens logs incomplets ne sont pas reconstruits. Un historique vide ne prouve pas qu’un code n’a jamais été utilisé. Un code réutilisé peut présenter plusieurs réservations.

Voir aussi la validation d’accès et la liste des codes.

Tâches et ménage : fonctionnement

Les opérations utilisent les tâches natives RéservPro. L’application employés et l’API consultent et mettent à jour les mêmes tâches.

Base bêta : https://beta.reservpro.com/api/. Clé de l’entreprise dans Authorization: Bearer. Dates et heures : America/Montreal.

Parcours d’intégration

  1. Consulter les départs du jour et à venir.
  2. Retrouver les tâches par réservation ou emplacement.
  3. Commencer ou terminer la tâche par API, ou dans l’application employés.
  4. Relire l’état effectif de l’emplacement.

Activer un modèle de ménage

Dans les modèles de tâches, choisir « Cette tâche confirme le ménage de l’emplacement ». Les tâches échues todo ou doing rendent l’emplacement non prêt. Les tâches futures à faire ne le bloquent pas aujourd’hui. Une tâche démarrée par anticipation compte immédiatement.

Lire l’état actuel

  • menage_a_faire : tâche échue ouverte.
  • menage_en_cours : au moins une tâche commencée.
  • pret : confirmation datée et aucune tâche échue ouverte.
  • inconnu : aucune confirmation datée, Pret=null.

Les tâches annulées et les tâches des réservations annulées sont exclues. Les anciennes tâches non terminées restent à faire; elles ne sont jamais complétées automatiquement.

Le ménage décrit la préparation actuelle à accueillir. Il ne bloque pas les réservations futures et ne remplace pas la disponibilité ou l’occupation.

Respecter les règles de tâches

Les modèles requires_report exigent les heures réelles et une note; la note est facultative pour une routine schedule. Les changements par API sont journalisés. Une tâche événementielle peut concerner plusieurs emplacements par sa réservation : sa confirmation affecte alors toutes ces affectations.

Départs du jour et à venir

GET/api/departsBêta

Retourne les réservations actives dont la date de fin se trouve dans la période choisie, avec leurs emplacements et tâches.

Paramètres

ParamètreRègle
DateDebut / DateFinDates YYYY-MM-DD, bornes inclusives. Par défaut : aujourd’hui et J+30. Maximum 366 jours.
IDService / IDEmplacementFiltres facultatifs.
Debut / LimiteOffset et nombre de réservations. Par défaut 0 et 100; maximum 100 par page.

Exemple

GET /api/departs?DateDebut=2026-09-08&DateFin=2026-09-08
Authorization: Bearer VOTRE_CLE_BETA

Réponse

data contient DateDebut, DateFin, FuseauHoraire, Total, Debut, Limite et Resultats.

Chaque réservation expose IDReservation, IDService, Service, DateDebut, DateFin, HeureDepart (valeur du dossier), DepartEnregistre, Emplacements et Taches. Les affectations contiennent leurs dates et le bloc Menage actuel. Les tâches incluent IDTache, Etat, IDEmplacement, DebutPrevu et Menage.

Cas particuliers

Les réservations sans code d’accès sont incluses. Sans emplacement, Emplacements est vide et MenageService fournit l’état du service. Un changement d’emplacement intermédiaire figure dans les affectations; il ne constitue pas un départ final.

Pour le suivi du travail, consulter les tâches natives. Ne pas utiliser la liste des codes comme inventaire des départs.

Exemple complet de réponse

Exemple fictif de structure; aucune réservation client réelle n’est reproduite.

{
  "success": true,
  "error": false,
  "endpoint": "departs",
  "IDEntreprise": 123,
  "data": {
    "DateDebut": "2026-09-15",
    "DateFin": "2026-09-15",
    "FuseauHoraire": "America/Montreal",
    "Total": 1,
    "Debut": 0,
    "Limite": 100,
    "Resultats": [
      {
        "IDReservation": 300,
        "IDService": 100,
        "Service": "Camping",
        "DateDebut": "2026-09-13",
        "DateFin": "2026-09-15",
        "HeureDepart": "11:00:00",
        "DepartEnregistre": false,
        "Emplacements": [
          {
            "IDAffectation": 400,
            "IDEmplacement": 200,
            "Nom": "Terrain 01",
            "DateDebut": "2026-09-13",
            "DateFin": "2026-09-15",
            "Menage": {
              "Statut": "inconnu",
              "Libelle": "Ménage non confirmé",
              "Pret": null,
              "TachesOuvertes": 0,
              "IDTaches": [],
              "DerniereCompletion": null
            }
          }
        ],
        "Taches": [
          {
            "IDTache": 456,
            "Etat": "todo",
            "IDEmplacement": 200,
            "DebutPrevu": "2026-09-15 11:00:00",
            "Menage": true
          }
        ],
        "MenageService": null
      }
    ]
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.DateDebut / DateFin / FuseauHorairestringPériode du filtre et fuseau des dates/heures.
data.Total / Debut / LimiteintegerTotal filtré, offset et taille de page.
data.Resultatsarray<object>Départs; [] si aucun.
IDReservation / IDServiceintegerRéservation et service.
Service / DateDebut / DateFin / HeureDepartstring | nullLibellé et valeurs enregistrées, heure éventuellement vide.
DepartEnregistrebooleanIndicateur de départ enregistré.
Emplacementsarray<object>Affectations, avec IDAffectation et IDEmplacement (integer), Nom, DateDebut, DateFin et Menage.
Tachesarray<object>Résumé des tâches : IDTache, Etat, IDEmplacement, DebutPrevu et Menage (boolean). Charger /api/taches pour la fiche complète.
MenageServiceobject | nullÉtat du service sans unité; null lorsqu’il y a des affectations d’emplacements.

Consulter et mettre à jour les tâches

GETPATCH/api/tachesBêta

Accéder aux tâches natives de l’entreprise, les commencer, les terminer, les rouvrir ou les annuler.

Paramètres

ParamètreRègle
GET : IDTache, IDReservation, IDEmplacement, IDServiceFiltres facultatifs. La recherche par emplacement inclut les tâches événementielles liées par réservation.
GET : Etat / MenageEtat : todo, doing, done, cancelled. Menage=1 limite aux modèles de ménage.
GET : DateDebut / DateFinFacultatives, à fournir ensemble. Filtrent le début prévu. Sans dates : inclut les retards. Maximum 366 jours.
GET : Debut / LimitePagination : 0 et 100 par défaut, 100 maximum.
PATCH : IDTache, Etat, EtatAttenduRequis dans le JSON. EtatAttendu est le dernier état lu; un conflit retourne 409.
PATCH : Rapport, DebutReel, FinReelleSelon le modèle. Heures au format YYYY-MM-DD HH:MM:SS; rapport de 5000 caractères maximum.
PATCH : DemarrageAnticipeBooléen true pour confirmer explicitement une tâche prévue plus tard.

Exemple

GET /api/taches?Menage=1&Etat=todo

PATCH /api/taches
Content-Type: application/json
Authorization: Bearer VOTRE_CLE_BETA

{"IDTache":456,"Etat":"doing","EtatAttendu":"todo"}

Réponse de lecture

data contient Total, Debut, Limite, FuseauHoraire et Resultats. Une tâche expose IDTache, Titre, Etat, IDService, IDEmplacement, IDEmplacements (affectations résolues), IDReservation, IDEmploye, DebutPrevu, FinPrevue, DebutReel, FinReelle, CompleteLe, Description, Menage et ModeCompletion.

Réponse de modification

{
  "success": true,
  "error": false,
  "endpoint": "taches",
  "IDEntreprise": 123,
  "data": {
    "IDTache": 456,
    "Etat": "doing",
    "DejaApplique": false
  },
  "request_id": "req_exemple"
}

Un réessai vers le même état retourne DejaApplique=true sans deuxième événement. Une tâche annulée ne peut pas être reprise par cette action. Une réouverture remet à zéro sa confirmation; le journal conserve le changement.

Rapports et droits

Les règles sont les mêmes que dans l’application employés : voir le fonctionnement du ménage. Les droits de la clé sont limités à son entreprise. La tâche n’est pas recréée et aucune ancienne tâche n’est complétée implicitement.

Exemple complet de lecture

Exemple fictif de structure, avec identifiants de démonstration. ModeCompletion reprend la valeur configurée du modèle.

{
  "success": true,
  "error": false,
  "endpoint": "taches",
  "IDEntreprise": 123,
  "data": {
    "FuseauHoraire": "America/Montreal",
    "Total": 1,
    "Debut": 0,
    "Limite": 100,
    "Resultats": [
      {
        "IDTache": 456,
        "Titre": "Préparer le terrain",
        "Etat": "todo",
        "IDService": 100,
        "IDEmplacement": 200,
        "IDEmplacements": [
          200
        ],
        "IDReservation": 300,
        "IDEmploye": 0,
        "DebutPrevu": "2026-09-15 11:00:00",
        "FinPrevue": "2026-09-15 12:00:00",
        "DebutReel": null,
        "FinReelle": null,
        "CompleteLe": null,
        "Description": "",
        "Menage": true,
        "ModeCompletion": "requires_report"
      }
    ]
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.Total / Debut / LimiteintegerTotal filtré, offset et taille de page.
data.Resultatsarray<object>Tâches; [] si aucune.
IDTache / IDService / IDEmplacement / IDReservation / IDEmployeintegerIdentifiants; une association absente peut être représentée par 0.
IDEmplacementsarray<integer>Affectations d’unités résolues pour la tâche.
Titre / Descriptionstring | nullTexte configuré.
Etatstringtodo, doing, done ou cancelled.
DebutPrevu / FinPrevue / DebutReel / FinReelle / CompleteLestring | nullDates/heures natives, généralement YYYY-MM-DD HH:MM:SS. Gérer null et les éventuelles valeurs historiques vides.
MenagebooleanTâche issue d’un modèle de ménage.
ModeCompletionstring | nullMode du modèle, utilisé pour les exigences de rapport et d’heures décrites dans la fiche ménage.
PATCH data.IDTache / Etat / DejaAppliqueinteger / string / booleanTâche modifiée, état obtenu et indication qu’un réessai n’a pas créé un second événement.

État de ménage d’un emplacement

GETPATCH/api/emplacement-statutBêta

Lire l’état actuel ou changer la tâche de ménage qui le détermine.

Paramètres

ParamètreRègle
IDEmplacementRequis pour GET et PATCH.
PATCH : IDTacheRequis. Tâche d’un modèle de ménage, liée à cet emplacement et à l’entreprise.
PATCH : Statutmenage_a_faire → todo; menage_en_cours → doing; pret → done.
PATCH : EtatAttenduDernier état natif lu : todo, doing ou done.
PATCH : Rapport, DebutReel, FinReelle, DemarrageAnticipeMêmes règles que PATCH /api/taches.

Exemple

PATCH /api/emplacement-statut
Content-Type: application/json
Authorization: Bearer VOTRE_CLE_BETA

{
  "IDEmplacement": 123, "IDTache": 456,
  "Statut": "pret", "EtatAttendu": "doing",
  "DebutReel": "2026-09-08 11:00:00",
  "FinReelle": "2026-09-08 11:45:00",
  "Rapport": "Ménage terminé et vérifié."
}

Réponse

data contient IDEmplacement, Nom, Menage, Tache et BloqueReservations=false. Le bloc Menage contient Statut, Libelle, Pret, TachesOuvertes, IDTaches et DerniereCompletion.

Lire l’état effectif

La confirmation d’une tâche peut réussir alors que Menage.Pret=false : d’autres tâches échues restent ouvertes. Toujours lire l’état retourné avant d’afficher « prêt ». Le système n’enregistre pas un second statut indépendant des tâches.

GET /api/emplacements expose également ce bloc. Sans confirmation datée, Pret vaut null. Le ménage n’est pas un blocage commercial des disponibilités futures.

Exemple complet de lecture

Exemple fictif sans confirmation de ménage.

{
  "success": true,
  "error": false,
  "endpoint": "emplacement-statut",
  "IDEntreprise": 123,
  "data": {
    "IDEmplacement": 200,
    "Nom": "Terrain 01",
    "Menage": {
      "Statut": "inconnu",
      "Libelle": "Ménage non confirmé",
      "Pret": null,
      "TachesOuvertes": 0,
      "IDTaches": [],
      "DerniereCompletion": null
    },
    "Tache": null,
    "BloqueReservations": false
  },
  "request_id": "req_exemple"
}
ChampType JSONDescription
data.IDEmplacement / Nominteger / stringUnité consultée.
data.Menage.Statutstringinconnu, menage_a_faire, menage_en_cours ou pret.
data.Menage.LibellestringTexte d’affichage.
data.Menage.Pretboolean | nulltrue = prêt; false = tâches ouvertes; null = aucune confirmation datée.
data.Menage.TachesOuvertes / IDTachesinteger / array<integer>Nombre et identifiants des tâches ouvertes prises en compte.
data.Menage.DerniereCompletionstring | nullDernière confirmation datée, ou null.
data.Tacheobject | nullnull en GET; résultat de transition (IDTache, Etat, DejaApplique) en PATCH.
data.BloqueReservationsbooleanfalse : le ménage ne constitue pas un blocage de vente.

Application Android employés

L’application RéservPro Employé utilise les mêmes tâches que les endpoints API.

Fonctions disponibles

  • Consulter les tâches assignées.
  • Commencer et terminer une tâche selon les droits de l’employé.
  • Fournir les heures réelles et les rapports requis.
  • Accéder aux outils d’entretien et aux échanges d’équipe autorisés.

Essayer en bêta

Télécharger l’application Android bêta Ouvrir le portail employés

Une connexion employé est requise. Version Android bêta 1.0.3-4, Android 7.0 minimum. Le portail est chargé depuis la bêta; les évolutions web du suivi des tâches ne nécessitent pas de nouvelle compilation de l’application.

Choisir le parcours

L’application peut couvrir directement le travail des employés. Les endpoints de tâches servent à connecter un outil externe lorsqu’il est nécessaire.

Exemples PHP / cURL

Fonction GET avec Bearer

function reservpro_api_get($endpoint, $apiKey, $params = []) {
    $base = 'https://beta.reservpro.com/api/';
    $url = $base . $endpoint . '?' . http_build_query($params);

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Accept: application/json',
            'Authorization: Bearer ' . $apiKey
        ],
        CURLOPT_TIMEOUT => 30
    ]);

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        return ['error' => true, 'message' => curl_error($ch)];
    }

    curl_close($ch);
    return json_decode($response, true);
}

Exemple services

$services = reservpro_api_get('services', 'VOTRE_CLE_API', [
    'Service_Publie' => 1,
    'Service_Reservable_Public' => 1,
    'Debut' => 0,
    'Limite' => 20
]);

Fonction POST JSON avec Bearer et idempotence

function reservpro_api_post($endpoint, $apiKey, $payload = [], $idempotencyKey = null) {
    $url = 'https://beta.reservpro.com/api/' . $endpoint;
    $json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $headers = [
        'Accept: application/json',
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
        'Content-Length: ' . strlen($json)
    ];
    if ($idempotencyKey !== null) {
        $headers[] = 'Idempotency-Key: ' . $idempotencyKey;
    }

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $json,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_TIMEOUT => 30
    ]);

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        return ['error' => true, 'message' => curl_error($ch)];
    }

    curl_close($ch);
    return json_decode($response, true);
}

Exemple disponibilité

$dispo = reservpro_api_post('disponibilite', 'VOTRE_CLE_API', [
    'IDService' => 35197,
    'Details' => [
        'Date_Debut' => '2026-07-10',
        'Date_Fin' => '2026-07-15',
        'Nbr_Adulte' => 2,
        'IDEmplacement' => 8832,
        'HeureDebut' => 0,
        'HeureDuree' => 0
    ]
]);

Exemple checkout en PHP

$checkout = reservpro_api_post(
    'checkout',
    'VOTRE_CLE_API',
    [
        'IDSession' => 'campingqc_123abc',
        'customer' => [
            'first_name' => 'Hugo',
            'last_name' => 'Girard',
            'email' => 'hugo@example.com',
            'phone' => '514-555-0199',
            'address1' => '123 rue Exemple',
            'city' => 'Montréal',
            'state' => 'QC',
            'country' => 'Canada',
            'postal_code' => 'H1H 1H1',
            'language' => 'fr'
        ],
        'iframe_origin' => 'https://reservation.partenaire.ca',
        'webhook_url' => 'https://reservation.partenaire.ca/webhooks/reservpro',
        'webhook_secret' => getenv('RESERVPRO_WEBHOOK_SECRET'),
        'partner_reference' => 'CQ-2026-000123',
        'metadata' => ['channel' => 'camping-quebec']
    ],
    'cq-commande-20260710-000123'
);

$iframeHtml = $checkout['checkout']['iframe_html'] ?? '';
$checkoutId = $checkout['checkout']['id'] ?? '';

Réponses d’erreur

Les erreurs suivent un format cohérent.

{
  "success": false,
  "error": true,
  "error_code": "invalid_api_key",
  "error_message": "Clé API invalide.",
  "request_id": "req_…"
}

Erreurs fréquentes

CodeMessageCause
400Paramètre requis manquantIDService, DateDebut, etc.
401Authentification requiseClé API absente ou invalide.
404IntrouvableRoute ou ressource non supportée ou inaccessible à ce compte.
405Méthode non autoriséeEx. GET sur /api/gate-access.
410Endpoint retiréEx. ancienne action confirmer de réservation.
413Corps trop volumineuxLa limite de 64 Kio est dépassée.
422Données invalidesFormat de session, origine, client ou autre champ invalide.
429Limite atteinteQuota IP/compte dépassé ou blocage temporaire après de mauvaises clés.
500Erreur interneRéessayer avec la même clé d’idempotence et transmettre le request_id au soutien.
503Service indisponibleLe module de checkout n’est pas initialisé ou est temporairement indisponible.

Notes d’implantation

Calendrier : pour une grille de disponibilité des 30 prochains jours, il est recommandé d’utiliser un endpoint rapide qui retourne les jours complets, plutôt que d’appeler la disponibilité détaillée pour chaque date.
Disponibilité détaillée : peut recevoir IDEmplacement dans Details pour vérifier un terrain précis.

Recommandation d’architecture

  • Utiliser /api/calendrier pour construire les vues calendrier.
  • Utiliser /api/disponibilite seulement au moment de valider un choix précis.
  • Conserver la clé API et le secret webhook uniquement côté serveur.
  • Conserver IDSession, IDCheckout, partner_reference et les clés d’idempotence afin de rapprocher les opérations.
  • Traiter webhooks et appels de reprise de façon idempotente.
  • Utiliser le polling du checkout comme secours et après tout signal provenant de l’iframe.

Activation côté RéservPro

Avant d’ouvrir le checkout aux partenaires, l’exploitant RéservPro doit appliquer la migration datée sql/20260816_partner_api_checkout.sql, définir RESERVPRO_WEBHOOK_ENCRYPTION_KEY dans l’environnement (une valeur Base64 représentant 32 octets est recommandée) et exécuter crontab_api_webhooks.php chaque minute avec cette même variable. Ce worker réconcilie les états, reprend les livraisons interrompues et distribue la file de webhooks. L’endpoint checkout retourne 503 checkout_schema_unavailable tant que la migration n’est pas appliquée et 503 checkout_configuration_unavailable si la clé dédiée est absente ou invalide.

  • Configurer le serveur HTTP, le proxy, le CDN et l’outil de suivi pour exclure ou masquer le chemin /api/payment/rpt_… des journaux d’accès : il contient une capacité temporaire.
  • Conserver les sorties du worker dans un journal supervisé et alerter sur les livraisons dead; ne pas rediriger silencieusement toutes les erreurs vers /dev/null.
  • Fournir la même clé dédiée au processus PHP-FPM et au cron, la sauvegarder hors du dépôt et prévoir une rotation contrôlée avant de remplacer sa valeur.
  • Le stockage local des quotas est séparé automatiquement par utilisateur système. Pour imposer un autre emplacement, définir RESERVPRO_API_RATE_DIR vers un chemin absolu privé, inscriptible par PHP-FPM et protégé en mode 0700.
  • La grâce de libération vaut 900 secondes par défaut. RESERVPRO_API_CHECKOUT_RELEASE_GRACE_SECONDS permet de la régler entre 60 et 86 400 secondes; PHP-FPM et le worker doivent recevoir la même valeur.
  • Un lease interne empêche le worker de libérer un panier pendant une confirmation ou une réponse fournisseur en cours. RESERVPRO_API_PAYMENT_PROCESSING_LEASE_SECONDS vaut 300 secondes par défaut (60 à 900); le régler au-dessus du délai maximal des passerelles.
  • Avant la production, tester une interruption immédiatement après un débit et activer un rapprochement durable auprès de chaque fournisseur autorisé. Le webhook envoyé au partenaire confirme l’état RéservPro, mais ne remplace pas la preuve entrante ou la réconciliation de la passerelle de paiement.

Parcours partenaire recommandé

  1. Obtenir la clé du commerce dans Profil de l’entreprise → Intégration et la conserver côté serveur.
  2. Lire catégories et services, puis les fiches, attributs et unités nécessaires.
  3. Consulter le calendrier et demander un calcul précis avec les participants, dates et équipements.
  4. Créer le panier via /api/reservation avec une IDSession propre au parcours client.
  5. Créer le checkout avec une clé d’idempotence stable pour la même opération. Le paiement passe par la page hébergée.
  6. Traiter les webhooks signés et relire le statut du checkout avant de confirmer le paiement. Une fermeture d’iframe ne prouve pas le succès.

Après un délai réseau sur une écriture, ne pas répéter aveuglément une création de réservation. Relire le panier; pour le checkout, réutiliser la même clé d’idempotence et le même corps. Pour les tâches, utiliser EtatAttendu et gérer 409. Une clé API donne accès au compte marchand : le serveur partenaire doit aussi isoler ses propres utilisateurs.

Contrats et exemples vérifiés

Les exemples du catalogue proviennent de lectures HTTP de Démo Camping en bêta au 9 septembre 2026. Les exemples métier fictifs sont signalés. Aucun exemple ne garantit une disponibilité future. Les champs existants sont conservés lors des enrichissements présentés ici; tester les intégrations en bêta avant une mise en production autorisée.