API publique v1

API publique v1 — Référence

Toutes les routes sont publiques (sans authentification) sous le préfixe /api/v1/book/{org_slug}.

Le contrat est figé. Toute évolution breaking passe par /api/v2/... et un nouveau SDK.

En-têtes de réponse

Toute réponse de la v1 inclut :

X-Staycore-API-Version: v1
Content-Type: application/json

Utilisé pour observabilité côté backend (combien de clients sur v1 vs legacy).

Enveloppe standard

// Succès
{
  "success": true,
  "data": { /* T */ },
  "message": "Optional"
}
 
// Échec
{
  "success": false,
  "message": "Description courte de l'erreur."
}

Endpoints

GET /api/v1/book/{slug}

Configuration de l’organisation + clé Stripe publique.

Réponse :

{
  "success": true,
  "data": {
    "organization": { "name": "Acme", "slug": "acme", "logo": null },
    "config": {
      "payment_mode": "full" | "deposit" | "request",
      "default_locale": "fr" | "en",
      "branding": {},
      "terms_url": null,
      "min_stay_nights": null,
      "max_stay_nights": null
    },
    "stripe_public_key": "pk_live_..."
  }
}

GET /api/v1/book/{slug}/properties

Liste des biens bookables.

GET /api/v1/book/{slug}/properties/{id}/availability

Calendrier de disponibilités (mois courant + suivants).

GET /api/v1/book/{slug}/properties/{id}/price

Query string :

ParamTypeRequis
check_inYYYY-MM-DD
check_outYYYY-MM-DD
guests_countinteger
coupon_codestring

POST /api/v1/book/{slug}/checkout

Body JSON :

{
  "property_id": 42,
  "guest_name": "Jean Dupont",
  "guest_email": "jean@example.com",
  "guest_phone": "+33...",
  "check_in": "2026-08-01",
  "check_out": "2026-08-05",
  "guests_count": 2,
  "message": "Anniversaire",
  "locale": "fr",
  "coupon_code": "WELCOME10"
}

Réponse 201 :

{
  "success": true,
  "data": {
    "booking_token": "abc123...",
    "payment_mode": "full",
    "total_amount": 500.00,
    "charge_amount": 500.00,
    "client_secret": "pi_..._secret_...",
    "stripe_public_key": "pk_live_..."
  }
}

Rate limit : 10 / minute.

POST /api/v1/book/{slug}/validate-coupon

Valider un code promo avant le checkout. Rate limit : 20 / minute.

GET /api/v1/book/{slug}/booking/{token}

Statut de la réservation par son token (page de suivi).

POST /api/v1/book/{slug}/booking/{token}/confirm

Confirmer la réservation après succès Stripe. Rate limit : 10 / minute.

CORS

L’origine appelante doit être autorisée. Deux options :

  1. Custom domain déclaré dans le dashboard Stay’Core (Settings → Custom domains) — *.stay-core.com et *.vercel.app sont autorisés en plus
  2. Allowed origins explicite dans BookingEngineConfig.allowed_origins côté backend

Voir le guide Custom domain.

Statuts d’erreur courants

CodeQuandAction
404Org inexistante, moteur public désactivé, propriété introuvableVérifier le slug, activer le moteur public
422Validation échouée, dispo non garantie, paiement non confirméLire message
429Rate limit dépasséBackoff et réessayer
500Bug serveur (rare)Réessayer, contacter support

Contrat figé

Le contrat de cette API est gardé par un test PHPUnit dans le backend (BookingContractTest.php). Tout changement qui casserait la compatibilité fait échouer le CI : tu peux te baser dessus en production sans risque de surprise.