{
  "openapi": "3.1.0",
  "info": {
    "title": "A L'Instant Suspendu — Agent API",
    "version": "1.0.0",
    "summary": "API publique pour la prise de rendez-vous par des agents IA (LLMs avec tool-use).",
    "description": "POC d'API exposée aux assistants conversationnels (Claude, ChatGPT, Gemini, etc.) pour consulter le catalogue de prestations, lister les disponibilités et créer un rendez-vous au nom d'une cliente.\n\nPas de paiement en ligne via cette API : tout RDV créé est en mode `sur place` — la cliente règle en arrivant. Si elle souhaite régler en ligne ou utiliser un code, elle passe par /reservation.\n\nProtection : ouvert (POC). Honeypot anti-bot. Validation email obligatoire. Aurélia voit le RDV dans /gestion/bookings/ et peut l'annuler si besoin.",
    "contact": {
      "name": "Aurélia / A L'Instant Suspendu",
      "url": "https://alinstantsuspendu.fr",
      "email": "contact@alinstantsuspendu.fr"
    },
    "license": {
      "name": "All rights reserved"
    }
  },
  "servers": [
    { "url": "https://alinstantsuspendu.fr", "description": "Production" }
  ],
  "paths": {
    "/api/agent/services.php": {
      "get": {
        "operationId": "listServices",
        "summary": "Liste des prestations actives",
        "description": "Retourne le catalogue des prestations actuellement proposées par Aurélia, avec leur durée, prix et description.",
        "responses": {
          "200": {
            "description": "Catalogue des prestations",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ServicesResponse" }
              }
            }
          }
        }
      }
    },
    "/api/agent/availability.php": {
      "get": {
        "operationId": "getAvailability",
        "summary": "Créneaux disponibles pour une prestation",
        "description": "Retourne les créneaux disponibles sur une fenêtre temporelle pour la prestation choisie. Respecte les horaires d'ouverture, les exceptions, les bookings existants et le délai minimum de réservation.",
        "parameters": [
          {
            "name": "service",
            "in": "query",
            "required": true,
            "schema": { "type": "string" },
            "description": "Slug de la prestation (ex : `head-spa-suspendu`). Obtenu via `listServices`.",
            "example": "head-spa-suspendu"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "format": "date" },
            "description": "Début de la fenêtre (YYYY-MM-DD). Défaut : aujourd'hui.",
            "example": "2026-06-01"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 60, "default": 14 },
            "description": "Nombre de jours à scanner. Max 60."
          }
        ],
        "responses": {
          "200": {
            "description": "Liste des jours avec créneaux disponibles",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AvailabilityResponse" }
              }
            }
          },
          "404": { "description": "Prestation inconnue" }
        }
      }
    },
    "/api/agent/booking.php": {
      "post": {
        "operationId": "createBooking",
        "summary": "Créer un rendez-vous",
        "description": "Crée un RDV en mode `sur place` (pas de paiement en ligne via cette API). La cliente reçoit un mail de confirmation avec un lien d'annulation / décalage.\n\n**Important** : l'agent DOIT avoir l'accord explicite de la cliente avant de réserver. Aucune réservation spéculative. Le prénom, nom et email saisis doivent être ceux de la cliente, pas de l'agent.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateBookingRequest" },
              "example": {
                "service":   "head-spa-suspendu",
                "date":      "2026-06-12",
                "time":      "14:30",
                "firstname": "Marie",
                "lastname":  "Dupont",
                "email":     "marie.dupont@example.fr",
                "phone":     "+33612345678",
                "notes":     "Légère allergie à la lavande"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "RDV créé, mail de confirmation envoyé",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreateBookingResponse" }
              }
            }
          },
          "400": { "description": "Paramètres invalides (détail dans `error` + `field`)" },
          "404": { "description": "Prestation inconnue ou inactive" },
          "409": { "description": "Créneau non disponible — re-fetcher /availability" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Service": {
        "type": "object",
        "properties": {
          "id":           { "type": "integer" },
          "slug":         { "type": "string", "example": "head-spa-suspendu" },
          "name":         { "type": "string", "example": "L'Instant Suspendu" },
          "description":  { "type": "string" },
          "duration_min": { "type": "integer", "description": "Durée du soin en minutes" },
          "price_cents":  { "type": "integer", "description": "Prix en centimes d'euros" },
          "price_label":  { "type": "string", "example": "75 €" },
          "category":     { "type": "string", "enum": ["head-spa", "beaute-du-regard", "rituels", "liftant-coreen"] }
        },
        "required": ["id", "slug", "name", "duration_min", "price_cents"]
      },
      "ServicesResponse": {
        "type": "object",
        "properties": {
          "ok":       { "type": "boolean" },
          "services": { "type": "array", "items": { "$ref": "#/components/schemas/Service" } }
        }
      },
      "DaySlots": {
        "type": "object",
        "properties": {
          "date":      { "type": "string", "format": "date", "example": "2026-06-12" },
          "day_label": { "type": "string", "example": "Vendredi 12 juin" },
          "slots":     {
            "type": "array",
            "items": {
              "type": "object",
              "properties": { "time": { "type": "string", "pattern": "^\\d{2}:\\d{2}$", "example": "14:30" } }
            }
          }
        }
      },
      "AvailabilityResponse": {
        "type": "object",
        "properties": {
          "ok":      { "type": "boolean" },
          "service": { "$ref": "#/components/schemas/Service" },
          "from":    { "type": "string", "format": "date" },
          "to":      { "type": "string", "format": "date" },
          "days":    { "type": "array", "items": { "$ref": "#/components/schemas/DaySlots" } }
        }
      },
      "CreateBookingRequest": {
        "type": "object",
        "required": ["service", "date", "time", "firstname", "lastname", "email"],
        "properties": {
          "service":   { "type": "string", "description": "Slug de la prestation" },
          "date":      { "type": "string", "format": "date" },
          "time":      { "type": "string", "pattern": "^\\d{2}:\\d{2}$" },
          "firstname": { "type": "string", "maxLength": 64 },
          "lastname":  { "type": "string", "maxLength": 64 },
          "email":     { "type": "string", "format": "email" },
          "phone":     { "type": "string", "maxLength": 32, "nullable": true },
          "notes":     { "type": "string", "maxLength": 500, "nullable": true, "description": "Message libre destiné à Aurélia (préférence, allergie, contrainte…)" }
        }
      },
      "CreateBookingResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "booking": {
            "type": "object",
            "properties": {
              "id":             { "type": "integer" },
              "service":        { "type": "object", "properties": { "slug": { "type": "string" }, "name": { "type": "string" }, "duration_min": { "type": "integer" } } },
              "start_at":       { "type": "string", "format": "date-time" },
              "end_at":         { "type": "string", "format": "date-time" },
              "status":         { "type": "string", "example": "confirmed" },
              "payment_mode":   { "type": "string", "example": "later" },
              "payment_status": { "type": "string", "example": "none" },
              "price_cents":    { "type": "integer" },
              "price_label":    { "type": "string" }
            }
          },
          "cancel_url":              { "type": "string", "format": "uri" },
          "reschedule_url":          { "type": "string", "format": "uri", "description": "Même URL que cancel_url ; la page proposera l'option Décaler ou Annuler définitivement." },
          "confirmation_email_sent": { "type": "boolean" }
        }
      }
    }
  }
}
