Documentation · Interface PMS

API Reference XML

URL unique, authentification, enveloppe <?Label?>, envoi et récupération des messages, accusés RESULT.

Staginghttps://staging.bridgchannel.appv1.0 · 2026-09-11<?Label BRIDG|DOC|1.0|NEW?>

Le modèle XML s'adresse aux PMS installés chez l'hôtel. Il parle le dialecte XML Fidelio d'Oracle OPERA (OXI) et repose sur un principe simple : toutes les connexions partent de l'hôtel. Bridg_ n'appelle jamais le PMS ; le PMS pousse ses messages vers Bridg_ et vient chercher ceux de Bridg_. Aucune adresse publique ni ouverture de pare-feu n'est nécessaire côté hôtel.

Identifiant d'adaptateur : opera-oxi. Cible validée : OPERA 5 on-premise avec OXI (module servlet) — voir Paramétrage Oracle OPERA / OXI. Tout PMS capable d'émettre et de lire ce dialecte peut utiliser ce modèle.

Pages du modèle XML :

Topologie

                         POST …/messages?key=<secret>   (le PMS envoie : ARI, réservations, RESULT, MessageRequest)
   PMS (OXI) ────────────────────────────────────────────▶  Bridg_
   PMS (OXI) ◀────────────────────────────────────────────  Bridg_
                         GET  …/messages?key=<secret>    (le PMS vient chercher : réservations OTA/directes, RESULT)

Une seule URL à configurer dans le PMS, pour l'envoi comme pour la réception :

{base}/api/pms/v1/connections/{connectionId}/messages

Authentification

Deux schémas sont acceptés sur chaque appel ; le premier est recommandé pour OXI, dont l'écran de configuration HTTP n'a pas de champ d'identifiants.

Schéma Comment Exemple
Clé dans l'URL (recommandé) paramètre de query key=<secret> …/messages?key=9f1e…
HTTP Basic Authorization: Basic base64(clientToken:secret) user = pms_3f9c…, password = secret
  • Si key est présent dans l'URL, il est seul évalué.
  • OXI ajoute ses propres paramètres à l'URL configurée (&propertyName=<code>&zipData=N) ; ils sont acceptés et ignorés. zipData doit rester à N (pas de compression).
  • Réponse 401 UNAUTHORIZED si la clé, l'identifiant ou le mot de passe est faux ; 404 si le connectionId est inconnu ; 403 CONNECTION_INACTIVE si la connexion est en pause.

L'enveloppe <?Label ?>

Tout message, dans les deux sens, commence par la déclaration XML puis l'instruction de traitement Label, qui sert au routage :

XML
<?xml version="1.0" encoding="UTF-8"?>
<?Label ATLALG|RTAV|2841178|NEW?>
Champ Position Description
propertyName 1 Code de l'établissement chez le PMS (externalPropertyCode de la connexion). Bridg_ le renvoie tel quel dans ses RESULT.
messageType 2 Type de message : RTAV, RATE, RAVL, RESTRICTION, RESERVATION, RESULT, MESSAGEREQUEST…
transactionId 3 Identifiant du message chez l'émetteur. Entier de 1 à 999999999 pour les messages servis par Bridg_ ; recommandé aussi pour ceux du PMS. C'est la clé de déduplication et de corrélation des RESULT.
status 4 NEW pour un message ordinaire ; SUCCESS ou FAILED pour un RESULT.

Un message sans Label est refusé 400 MISSING_LABEL ; un Label à moins de 4 champs, 400 MALFORMED_LABEL. Aucun champ ne peut contenir | ni ?.

Types de message

messageType Sens Contenu Support
RTAV PMS → Bridg_ disponibilité par type de chambre et par nuit ✅ détail
RATE PMS → Bridg_ prix par plan tarifaire (DETAIL, HEADERWITHDETAIL) ; un HEADER est acquitté sans effet ✅ détail
RAVL PMS → Bridg_ restrictions par code tarifaire ✅ détail
RESTRICTION PMS → Bridg_ restrictions par tarif × type de chambre ✅ détail
RESERVATION PMS → Bridg_ réservation créée, modifiée ou annulée dans le PMS ✅ détail
RESERVATION Bridg_ → PMS réservation OTA ou directe (servie par GET) ✅ détail
RESULT les deux sens accusé de traitement ✅ détail
MESSAGEREQUEST PMS → Bridg_ redemande d'une RESERVATION perdue ✅ (type RESERVATION seulement)
RAVR PMS → Bridg_ restrictions par type de chambre ❌ RESULT FAILED RESTRICTION_GRANULARITY_MISMATCH — utiliser RAVL
INVENTORY, ALLOTMENT, HURDLE PMS → Bridg_ hors-service et limites de vente, allotements, hurdles ❌ RESULT FAILED UNSUPPORTED_MESSAGE_TYPE
PROFILE, STAY, PACKAGES, autres PMS → Bridg_ ❌ RESULT FAILED UNSUPPORTED_MESSAGE_TYPE

Un message d'un type non supporté est acquitté par un RESULT d'échec (réponse HTTP 200), jamais par un 4xx : le PMS peut ainsi continuer à envoyer ce type sans bloquer sa file, et l'hôtelier voit le refus dans le journal.

Envoyer un message

Request

POST{base}/api/pms/v1/connections/{connectionId}/messages?key={secret}
Content-Type: text/xml; charset=UTF-8
XML
<?xml version="1.0" encoding="UTF-8"?>
<?Label ATLALG|RTAV|2841178|NEW?>
<RtavMessage xmlns="rtav.fidelio.4.0">
  <HotelReference hotelCode="ATLALG"/>
  <DailyInventories>
    <DailyInventory datum="2026-10-10">
      <RoomTypeInventories>
        <RoomTypeInventory roomType="DLX" physicalRooms="20" outOfOrder="1" available="12" roomTypeOverbook="2"/>
      </RoomTypeInventories>
    </DailyInventory>
  </DailyInventories>
</RtavMessage>
curl
curl -X POST "https://staging.bridgchannel.app/api/pms/v1/connections/$CONNECTION_ID/messages?key=$SECRET" \
  -H "Content-Type: text/xml; charset=UTF-8" \
  --data-binary @rtav.xml

Success Response

200 OK — le message est reçu et persisté. Le verdict de traitement est un RESULT mis en file, à récupérer par GET. Le corps de la réponse contient, à titre indicatif, le même RESULT (text/xml) pour un message ARI, ou un objet JSON pour les autres types ; OXI n'en lit pas le contenu.

Avec le réglage Traitement en arrière-plan (onglet Réglages de la connexion), la réponse part dès que le message est enregistré — { "accepted": true, "queued": true, "messageId": "…" } — et l'application suit, dans l'ordre d'arrivée, message par message. Le verdict arrive comme toujours en RESULT par le GET. Sans ce réglage, la réponse n'est faite qu'une fois le message appliqué : OXI, qui attend chaque réponse avant d'envoyer le message suivant, reste bloqué le temps de l'application (un code tarifaire entier : ~20 s).

XML
<?xml version="1.0" encoding="UTF-8"?>
<?Label ATLALG|RESULT|2841178|SUCCESS?>
<RESULT xmlns="result.fidelio.4.0" success="SUCCESS" timeStamp="2026-09-11T10:39:18.895">
  <resortId>ATLALG</resortId>
  <resultMessage>Successfully applied in Bridg Channel Manager</resultMessage>
</RESULT>

Message ARI appliqué en partie (des éléments refusés — le plus souvent un code non associé —, les autres écrits) : succès avec réserve, enveloppe SUCCESS et corps success="WARNING", les éléments refusés nommés dans resultMessage. FAIL est réservé au message dont rien n'a été appliqué. Le texte de resultMessage est en ASCII (sans accents) : la base OPERA des sites observés n'est pas en UTF-8.

XML
<?Label ALGAA|RESULT|334209|SUCCESS?>
<RESULT xmlns="result.fidelio.4.0" success="WARNING" timeStamp="2026-09-30T16:50:27.101">
  <resortId>ALGAA</resortId>
  <resultMessage>196 item(s) rejete(s) : #0 UNMAPPED_UNIT_TYPE - Type d'unite "SUI" non mappe sur cette connexion | …</resultMessage>
</RESULT>

Codes ignorés par l'établissement (non vendus en ligne, déclarés dans l'onglet Correspondance des codes) : leurs éléments sont acquittés sans être appliqués, et comptent comme un succès — Successfully applied in Bridg Channel Manager — 888 item(s) ignoré(s), codes non vendus : SWIFT2.

200 OK avec verdict négatif en file (type non supporté, code non mappé, message illisible mais enveloppe lisible) :

JSON
{ "accepted": true, "verdictQueued": true }

202 Accepted — même transactionId reçu à nouveau pendant son traitement ; ne pas réémettre.

Error Response

400 Bad Request — enveloppe absente ou malformée (aucune corrélation possible) :

JSON
{ "error": "Instruction <?Label ...?> absente — enveloppe OXI obligatoire", "code": "MISSING_LABEL" }

401 Unauthorized · 403 Forbidden (CONNECTION_INACTIVE) · 404 Not Found · 429 Too Many Requests

500 Internal Server Error — échec transitoire ; le message est conservé et rejoué côté Bridg_, et le PMS doit le réémettre après un délai :

JSON
{ "error": "Message reçu mais non appliqué — reprise programmée", "code": "INGEST_FAILED" }

Returns

Cas HTTP Verdict
Message appliqué 200 RESULT SUCCESS en file
Message appliqué partiellement (items refusés) 200 RESULT FAILED en file, resultMessage détaille les items (#0 UNMAPPED_UNIT_TYPE — …)
Type non supporté, restriction non traduisible, corps illisible 200 RESULT FAILED en file
Doublon déjà traité 200 accusé mémorisé, pas de nouveau RESULT
Doublon en cours de traitement 202 —
Enveloppe illisible 400 —
Échec transitoire 500 réémettre

Récupérer le prochain message

Le PMS vient chercher, un message par appel, dans l'ordre FIFO : réservations OTA et directes (RESERVATION) et accusés de traitement (RESULT) des messages qu'il a envoyés.

Request

GET{base}/api/pms/v1/connections/{connectionId}/messages?key={secret}
curl
curl -i "https://staging.bridgchannel.app/api/pms/v1/connections/$CONNECTION_ID/messages?key=$SECRET"

Success Response

200 OK avec un message. L'en-tête HTTP title reprend l'enveloppe et permet de router sans parser le corps.

HTTP/1.1 200 OK
Content-Type: text/xml; charset=UTF-8
title: ATLALG|RESERVATION|42|NEW

<?xml version="1.0" encoding="UTF-8"?>
<?Label ATLALG|RESERVATION|42|NEW?>
<Reservation xmlns="reservation.fidelio.4.0" mfReservationAction="ADD">
  …
</Reservation>

200 OK sans message : corps vide et Content-Length: 0 (jamais un 204).

HTTP/1.1 200 OK
Content-Length: 0

Error Response

401 Unauthorized · 403 Forbidden (CONNECTION_INACTIVE) · 404 Not Found · 429 Too Many Requests

Returns

Cas Réponse
Un message est en attente 200, corps XML, en-tête title
Rien en attente 200, Content-Length: 0

Note

  • Rythme : interroger toutes les 30 à 120 secondes ; quand un message est servi, ré-interroger immédiatement jusqu'à obtenir un corps vide.
  • Une RESERVATION servie reste en attente de votre RESULT (corrélé sur son transactionId). Sans RESULT sous 30 minutes, elle est resservie avec un nouveau transactionId : dédupliquez sur reservationID.
  • Un RESULT servi n'attend rien en retour.
  • L'ordre est garanti par réservation : la modification d'une réservation n'est jamais servie avant sa création ; une réservation en dead-letter bloque ses propres événements suivants, pas ceux des autres réservations.

Accusés de traitement

Le protocole est asynchrone par construction : la réponse HTTP n'accuse que la réception.

Sens Message Verdict Corrélation
PMS → Bridg_ ARI, réservation, MessageRequest RESULT mis en file par Bridg_, récupéré par GET transactionId du message du PMS
Bridg_ → PMS RESERVATION servie par GET RESULT envoyé par le PMS sur POST …/messages transactionId que Bridg_ a posé sur la réservation

Format et sémantique du RESULT : reservations.md.

Conventions de dates

Forme Où Sémantique
<TimeSpan timeUnitType="DAY"><startTime>2026-10-10T00:00:00.000</startTime><numberOfTimeUnits>3</numberOfTimeUnits></TimeSpan> RAVL, RESTRICTION, RESERVATION première nuit + nombre de nuits (1 à 3 700). DAY uniquement.
<DaysOfWeek><monday>1</monday>…</DaysOfWeek> RAVL, RESTRICTION, RATE (RateDaysOfWeek) masque jour-de-semaine appliqué à la plage ; absent ou tout à 1 = toute la plage. 1, Y, true = actif.
<startDate>2026-10-10</startDate><endDate>2026-10-12</endDate> RATE endDate inclusive par défaut (rateEndDateInclusive).
datum="2026-10-10" RTAV une nuit.

Les dates sont des dates civiles ; la partie heure de startTime est ignorée.

Codes d'erreur propres au XML

code Cause
MISSING_LABEL, MALFORMED_LABEL enveloppe absente ou incomplète (HTTP 400)
UNEXPECTED_MESSAGE élément racine inattendu pour le type annoncé
INVALID_TIMESPAN, INVALID_DATE_RANGE TimeSpan ou startDate/endDate illisibles ou hors bornes
UNSUPPORTED_MESSAGE_TYPE type non traduit (INVENTORY, PROFILE…)
RESTRICTION_GRANULARITY_MISMATCH RAVR — utiliser RAVL
UNSUPPORTED_RESTRICTION code de restriction sans équivalent (ADVBOOK_MIN…)
UNSUPPORTED_ROOM_CLASS, UNSUPPORTED_RATE_CATEGORY, UNSUPPORTED_SCOPE, UNSUPPORTED_BLOCK_RESTRICTION restriction par classe, catégorie, hôtel entier ou bloc
UNSUPPORTED_TIERED_RATE, UNSUPPORTED_WEEKEND_RATE, UNSUPPORTED_RATE_MESSAGE tarifs par durée de séjour, prix week-end, rateMessageType inconnu
UNSUPPORTED_TIME_UNIT timeUnitType autre que DAY
MISSING_RATE_CODE, MISSING_RESTRICTION_CODE, MISSING_REFERENCE, MISSING_AMOUNT, DUPLICATE_NIGHT, NEGATIVE_COUNT champ requis absent ou incohérent