Aller au contenu

Suivre les statuts

Ce guide explique comment synchroniser les statuts de paiement avec votre PMS.

Stratégie de synchronisation

Deux approches complémentaires :

Méthode Usage Latence
Polling (GET statuses + mark-retrieved) Synchronisation batch périodique Quelques minutes
Webhooks (IPN) Notification en temps réel Quelques secondes

Synchronisation incrémentale

L'endpoint /statuses/ retourne par défaut uniquement ce qui est nouveau ou a changé depuis le dernier acquittement du PMS. Couplé à POST /mark-retrieved/, il forme un flux de sync incrémental sans doublons.

Principe

  1. FetchGET /statuses/ retourne :
    • les demandes jamais acquittées (= nouvelles créations)
    • les demandes acquittées mais modifiées depuis (ex. passage en CAPTURED via webhook)
  2. Process — le PMS traite chaque demande (création d'arrhes, mise à jour du séjour, etc.)
  3. AckPOST /mark-retrieved/ avec les UUIDs traités
  4. Boucle — au prochain fetch, seules les évolutions ultérieures remontent

Pourquoi ré-acquitter les statuts qui changent

Si le PMS acquitte une demande en PENDING, puis le guest paye (webhook → CAPTURED), la demande réapparaît automatiquement au prochain fetch. Le PMS peut alors mettre à jour son enregistrement et ré-acquitter.

Requête — fetch incrémental

curl -H "X-API-Key: votre-clé-api" \
  "https://votre-domaine.com/api/payment-requests/statuses/"

Requête — acquittement

curl -X POST \
  -H "X-API-Key: votre-clé-api" \
  -H "Content-Type: application/json" \
  -d '{"uuids": ["550e8400-...", "7c9e6679-..."]}' \
  https://votre-domaine.com/api/payment-requests/mark-retrieved/

Réponse :

{"marked": 2}

Snapshot complet

Pour une réconciliation périodique ou un audit, récupérez l'intégralité en ignorant l'acquittement :

curl -H "X-API-Key: votre-clé-api" \
  "https://votre-domaine.com/api/payment-requests/statuses/?include_retrieved=true"

Réponse type /statuses/

[
  {
    "uuid": "550e8400-...",
    "reference": "DEP-2026-0042",
    "reservation_ref": "RES-001",
    "request_type": "DEPOSIT",
    "status": "CAPTURED",
    "order_cycle": "CLOSED",
    "amount": 150.00,
    "amount_captured": 150.00
  },
  {
    "uuid": "7c9e6679-...",
    "reference": "IMP-2026-0015",
    "reservation_ref": "RES-002",
    "request_type": "IMPRINT",
    "status": "AUTHORISED",
    "order_cycle": "OPEN",
    "amount": 200.00,
    "amount_captured": 0.00
  }
]

Fréquence recommandée

Synchronisez toutes les 5 à 10 minutes pour un bon compromis entre fraîcheur des données et charge serveur.

Liste filtrée par statut

Pour récupérer toutes les demandes dans un statut donné :

# Toutes les demandes en attente
curl -H "X-API-Key: votre-clé-api" \
  "https://votre-domaine.com/api/payment-requests/?status=PENDING"

Statuts de référence

Statut Code Terminal Description
Non initié NOT_INITIATED Non Demande créée, formulaire non ouvert
En attente PENDING Non Formulaire ouvert par le client
Autorisé AUTHORISED Non Paiement autorisé (empreinte enregistrée)
A valider AUTHORISED_TO_VALIDATE Non Pré-autorisation en attente de capture
Capturé CAPTURED Oui Montant débité
Refusé REFUSED Oui Refusé par la banque
Erreur ERROR Non Erreur technique
Annulé CANCELLED Oui Annulé par l'hôtel
Expiré EXPIRED Oui Délai dépassé
Remboursé REFUNDED Oui Montant remboursé

Champ order_cycle

Valeur Signification
OPEN Transaction en cours
CLOSED Transaction terminée

Exemple d'intégration PMS

import requests

API_KEY = "votre-clé-api"
BASE_URL = "https://votre-domaine.com/api"
HEADERS = {"X-API-Key": API_KEY}


def fetch_pending() -> list[dict]:
    """Récupère les demandes non acquittées ou modifiées depuis le dernier ack."""
    response = requests.get(
        f"{BASE_URL}/payment-requests/statuses/",
        headers=HEADERS,
    )
    response.raise_for_status()
    return response.json()


def mark_retrieved(uuids: list[str]) -> int:
    """Acquitte un lot d'UUIDs côté M-Pay. Retourne le nombre de lignes mises à jour."""
    if not uuids:
        return 0
    response = requests.post(
        f"{BASE_URL}/payment-requests/mark-retrieved/",
        json={"uuids": uuids},
        headers=HEADERS,
    )
    response.raise_for_status()
    return response.json()["marked"]


def sync_cycle():
    """Un cycle complet : fetch → process → ack."""
    pending = fetch_pending()
    if not pending:
        return

    processed = []
    for item in pending:
        try:
            handle_in_pms(item)  # création d'arrhes, mise à jour séjour, etc.
            processed.append(item["uuid"])
        except Exception:
            # En cas d'erreur, on n'acquitte pas -> la demande reviendra au prochain cycle
            continue

    mark_retrieved(processed)


def handle_in_pms(item: dict):
    """Logique métier PMS. À implémenter selon votre logiciel."""
    ...


# Exécution périodique (cron, Celery beat, etc.)
sync_cycle()

Ne pas acquitter ce qui n'a pas été traité

N'incluez dans mark-retrieved que les UUIDs réellement persistés côté PMS. Si le traitement échoue, laissez la demande non acquittée : elle réapparaîtra au prochain fetch.