{
  "openapi": "3.0.0",
  "paths": {
    "/api/order/refund": {
      "post": {
        "description": "Déclare une commande annulée, remboursée ou partiellement remboursée et déduit les points de fidélité correspondants. Les montants et quantités sont **cumulés** depuis l'origine de la commande, jamais le delta de l'avoir courant : rejouer un même avoir est sans effet, un avoir supplémentaire ne déduit que son propre delta. Le traitement est asynchrone ; une commande inconnue de la boutique renvoie aussi un succès et est journalisée côté serveur.",
        "operationId": "OrderController_refundApiOrder",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefundDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderRefundedResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "401": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "security": [
          {
            "basic": []
          }
        ],
        "summary": "Annuler ou rembourser une commande",
        "tags": ["API : commandes"],
        "x-internal-events": ["ORDER_REFUNDED", "POINTS_DEDUCTED"]
      }
    },
    "/api/order/register": {
      "post": {
        "description": "Enregistre une commande avec le contrat historique `2026-01-01`, dans lequel l'identifiant de commande est transmis dans le champ `externalRef`.",
        "operationId": "OrderController_registerApiOrder",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Order20260101Dto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderRegisteredResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "401": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "security": [
          {
            "basic": []
          }
        ],
        "summary": "Enregistrer une commande",
        "tags": ["API : commandes"],
        "x-internal-events": ["ORDER_REGISTERED", "POINTS_EARNED"]
      }
    },
    "/point/product-points/calculate": {
      "get": {
        "description": "Retourne le nombre de points qu’une commande de ce produit rapporterait au client, d’après les règles d’attribution actives de la boutique. La règle retenue est précisée dans `type` (produit, catégorie ou règle par défaut) et son identifiant dans `id`.",
        "operationId": "ProductPointsController_calculateProductPoints",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "product",
            "required": false,
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "categories",
            "required": false,
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "number"
              }
            }
          },
          {
            "name": "price",
            "required": true,
            "in": "query",
            "schema": {
              "minimum": 1,
              "type": "number"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "schema": {
              "minLength": 6,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductPointsCalculateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "404": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Calculer les points gagnés pour un produit",
        "tags": ["Widget : produit"]
      }
    },
    "/point/referral": {
      "post": {
        "description": "Enregistre le parrainage d’un filleul par le client identifié par `externalId`, et lui envoie l’email d’invitation. Renvoie le `hash` du parrainage, à transmettre au filleul pour qu’il récupère son code. Répond `400` si le filleul est déjà client de la boutique ou déjà parrainé.",
        "operationId": "ReferralCreationController_createReferral",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "externalId",
            "required": true,
            "in": "query",
            "description": "Identifiant du parrain dans la boutique.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "hash",
            "required": true,
            "in": "query",
            "description": "HMAC SHA-512 de l’`externalId`, calculé avec la clé `<référence boutique>:<clé API>`.",
            "schema": {}
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "description": "Domaine de la boutique, tel que déclaré dans Enkore.",
            "schema": {}
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReferralDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateReferralResponse"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "401": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Créer un parrainage",
        "tags": ["Widget : parrainage"]
      }
    },
    "/point/user-history/{externalId}": {
      "get": {
        "description": "Retourne le solde de points du client, son historique de transactions et le club (palier) auquel il appartient. Le client est identifié par son identifiant dans la boutique (`externalId`), authentifié par le couple `domain` + `hash`.",
        "operationId": "HistoryController_getHistory",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "externalId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "hash",
            "required": true,
            "in": "query",
            "description": "HMAC SHA-512 de l’`externalId`, calculé avec la clé `<référence boutique>:<clé API>`.",
            "schema": {}
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "description": "Domaine de la boutique, tel que déclaré dans Enkore.",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreFrontHistoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "401": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Obtenir le solde et l’historique de points d’un client",
        "tags": ["Historique client"]
      }
    },
    "/reward/claim/{externalId}": {
      "post": {
        "description": "Débite le client du coût en points de la récompense et renvoie le code du bon de réduction généré. Répond `404` avec un `code` nul lorsque la récompense ne peut pas être obtenue (solde insuffisant, bon inactif ou limite d’utilisation atteinte).",
        "operationId": "RewardController_claimReward",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "externalId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "hash",
            "required": true,
            "in": "query",
            "description": "HMAC SHA-512 de l’`externalId`, calculé avec la clé `<référence boutique>:<clé API>`.",
            "schema": {}
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "description": "Domaine de la boutique, tel que déclaré dans Enkore.",
            "schema": {}
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimRewardDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClaimRewardResponse"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "401": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "404": {
            "description": "La récompense n’a pas pu être obtenue (solde insuffisant, bon inactif, limite atteinte) : le corps de l’échange est servi avec un `code` nul. Un client inconnu de la boutique donne, lui, un refus.\n\nCette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "nullable": true,
                          "description": "Code du bon obtenu, `null` si l’échange est refusé."
                        }
                      }
                    },
                    {
                      "$ref": "#/components/schemas/LegacyError"
                    }
                  ]
                }
              }
            }
          },
          "422": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "502": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Échanger des points contre une récompense",
        "tags": ["Récompenses"],
        "x-internal-events": ["REWARD_OBTAINED"]
      }
    },
    "/reward/list": {
      "get": {
        "description": "Retourne le catalogue des récompenses de la boutique achetables en points, triées par coût croissant (`triggerValue`). Seule la version courante de chaque bon est renvoyée ; les récompenses sans bon actif sont omises.",
        "operationId": "RewardController_getRewardsByStore",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "description": "Domaine de la boutique, tel que déclaré dans Enkore.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RewardByStoreCustomerResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "404": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Lister les récompenses échangeables contre des points",
        "tags": ["Récompenses"]
      }
    },
    "/reward/referral/get-referee-code": {
      "post": {
        "description": "Retourne le code de réduction attribué au filleul à partir du `referral-hash` reçu dans son email d’invitation.",
        "operationId": "ReferralRewardController_getRefereeCode",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRefereeCodeDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetRefereeCodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "404": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "422": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "502": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Obtenir le code de réduction d’un filleul",
        "tags": ["Widget : parrainage"]
      }
    },
    "/store/widget/cart": {
      "get": {
        "description": "Retourne la configuration du widget panier établie dans le back-office.",
        "operationId": "WidgetController_getCartConfiguration",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CartWidgetContent"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "404": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Obtenir la configuration du widget",
        "tags": ["Widget : panier"]
      }
    },
    "/store/widget/product-points": {
      "get": {
        "description": "Retourne la configuration du widget établie dans le back-office.",
        "operationId": "WidgetController_getProductPointsWidgetConfiguration",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductPointsWidgetContent"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "404": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Obtenir la configuration du widget",
        "tags": ["Widget : produit"]
      }
    },
    "/store/widget/program-presentation": {
      "get": {
        "description": "Retourne la configuration du widget de présentation du programme établie dans le back-office.",
        "operationId": "WidgetController_getProgramPresentationConfiguration",
        "parameters": [
          {
            "name": "revision",
            "in": "header",
            "required": true,
            "description": "Révision du contrat de l'API. Cette page décrit la révision 2026-01-01.",
            "schema": {
              "type": "string",
              "enum": ["2026-01-01"],
              "default": "2026-01-01"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PresentationWidgetContent"
                }
              }
            }
          },
          "400": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "404": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          },
          "500": {
            "description": "Cette révision sert le format d'erreur historique. Le champ `type`, stable par motif de refus, n'est servi qu'à partir de la révision `2026-08-26`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyError"
                }
              }
            }
          }
        },
        "summary": "Obtenir la configuration du widget",
        "tags": ["Widget : présentation du programme"]
      }
    }
  },
  "info": {
    "title": "Enkore",
    "description": "Documentation de l'API publique Enkore pour la révision 2026-01-01.",
    "version": "2026-01-01",
    "contact": {}
  },
  "tags": [],
  "servers": [
    {
      "url": "https://api.enkore.io"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http"
      },
      "basic": {
        "type": "http",
        "scheme": "basic"
      }
    },
    "schemas": {
      "PresentationHeaderSection": {
        "type": "object",
        "properties": {
          "backgroundImageUrl": {
            "type": "string",
            "description": "Image de bannière affichée sur desktop."
          },
          "mobileBackgroundImageUrl": {
            "type": "string",
            "description": "Image de bannière affichée sur mobile ; chaîne vide pour réutiliser celle du desktop."
          },
          "imageFit": {
            "type": "string",
            "description": "Cadrage de l'image : `cover` (rognée, hauteur fixe) ou `ratio` (ratio de l'image).",
            "enum": ["cover", "ratio"]
          },
          "mobileLayout": {
            "type": "string",
            "description": "Disposition mobile : `overlay` (texte sur l'image) ou `stacked` (texte sous l'image).",
            "enum": ["overlay", "stacked"]
          },
          "contentPosition": {
            "type": "string",
            "description": "Position du bloc de texte dans la bannière.",
            "enum": ["center", "left", "right"]
          },
          "contentCard": {
            "type": "boolean",
            "description": "`true` pour poser le texte sur une carte opaque plutôt que directement sur l'image."
          },
          "backgroundColor": {
            "type": "string",
            "description": "Couleur de fond de la bannière ; retombe sur celle du branding si non renseignée."
          },
          "textColor": {
            "type": "string",
            "description": "Couleur du texte de la bannière."
          },
          "primaryButtonText": {
            "type": "string",
            "description": "Libellé du bouton principal, dans la langue par défaut de la boutique."
          },
          "primaryButtonAction": {
            "type": "string",
            "description": "Action du bouton principal : défilement vers une section ou ouverture d'une URL.",
            "enum": [
              "scroll-points",
              "scroll-redeem",
              "scroll-history",
              "scroll-faq",
              "url"
            ]
          },
          "primaryButtonUrl": {
            "type": "string",
            "description": "URL ouverte par le bouton principal quand son action vaut `url`."
          },
          "secondaryButtonText": {
            "type": "string",
            "description": "Libellé du bouton secondaire, dans la langue par défaut de la boutique."
          },
          "secondaryButtonAction": {
            "type": "string",
            "description": "Action du bouton secondaire : défilement vers une section ou ouverture d'une URL.",
            "enum": [
              "scroll-points",
              "scroll-redeem",
              "scroll-history",
              "scroll-faq",
              "url"
            ]
          },
          "secondaryButtonUrl": {
            "type": "string",
            "description": "URL ouverte par le bouton secondaire quand son action vaut `url`."
          },
          "text": {
            "type": "string",
            "description": "Contenu de la bannière, dans la langue par défaut de la boutique."
          },
          "isRawHtml": {
            "type": "boolean",
            "description": "`true` lorsque `text` est du HTML brut rédigé par la boutique."
          }
        },
        "required": [
          "mobileBackgroundImageUrl",
          "imageFit",
          "mobileLayout",
          "contentPosition",
          "contentCard",
          "backgroundColor",
          "textColor",
          "primaryButtonText",
          "primaryButtonAction",
          "primaryButtonUrl",
          "secondaryButtonText",
          "secondaryButtonAction",
          "secondaryButtonUrl",
          "text",
          "isRawHtml"
        ]
      },
      "PresentationTextSection": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Contenu de la section, dans la langue par défaut de la boutique."
          },
          "backgroundColor": {
            "type": "string",
            "description": "Couleur de fond de la section, héritée du branding de la boutique."
          },
          "isRawHtml": {
            "type": "boolean",
            "description": "When true the section renders `text` in a bare container, without the\ndecorative classes of the standard layout. Merchant-authored markup then\nowns the whole section."
          }
        },
        "required": ["text", "backgroundColor", "isRawHtml"]
      },
      "PresentationFAQSection": {
        "type": "object",
        "properties": {
          "backgroundColor": {
            "type": "string",
            "description": "Couleur de fond de la section, héritée du branding de la boutique."
          }
        },
        "required": ["backgroundColor"]
      },
      "PresentationReferralSection": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Contenu de la section, dans la langue par défaut de la boutique."
          },
          "backgroundColor": {
            "type": "string",
            "description": "Couleur de fond de la section, héritée du branding de la boutique."
          },
          "display": {
            "type": "boolean",
            "description": "`false` pour masquer la section de parrainage."
          },
          "buttonBackgroundColor": {
            "type": "string",
            "description": "Couleur de fond du bouton de parrainage."
          },
          "buttonTextColor": {
            "type": "string",
            "description": "Couleur du texte du bouton de parrainage."
          },
          "isRawHtml": {
            "type": "boolean",
            "description": "`true` lorsque `text` est du HTML brut rédigé par la boutique."
          }
        },
        "required": ["text", "backgroundColor", "isRawHtml"]
      },
      "PresentationWidgetContent": {
        "type": "object",
        "properties": {
          "headerSection": {
            "description": "Bannière de la page programme.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PresentationHeaderSection"
              }
            ]
          },
          "historySection": {
            "description": "Section listant l'historique de points du client.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PresentationTextSection"
              }
            ]
          },
          "pointSystemSection": {
            "description": "Section expliquant comment gagner des points.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PresentationTextSection"
              }
            ]
          },
          "redeemSection": {
            "description": "Section expliquant comment utiliser ses points.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PresentationTextSection"
              }
            ]
          },
          "FAQSection": {
            "description": "Section foire aux questions.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PresentationFAQSection"
              }
            ]
          },
          "referralSection": {
            "description": "Section de parrainage.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PresentationReferralSection"
              }
            ]
          },
          "customCss": {
            "type": "string",
            "description": "CSS additionnel injecté par la boutique."
          },
          "defaultLanguage": {
            "type": "string",
            "description": "Code ISO de la langue par défaut de la boutique."
          },
          "loginUrl": {
            "type": "string",
            "description": "URL de la page de connexion de la boutique, dérivée de sa plateforme\n(`store.platform`). Vide quand la plateforme n'en expose pas de dérivable —\nc'est le cas des intégrations `api`, sur mesure par nature. Le widget ne\nrend son état déconnecté cliquable que sur une valeur non vide."
          },
          "translations": {
            "type": "object",
            "additionalProperties": true,
            "description": "Textes indexés par code ISO de langue (`fr`, `en`…). Chaque valeur porte les\nclés de `PresentationWidgetTranslation` : `headerText`,\n`headerPrimaryButtonText`, `headerSecondaryButtonText`, `historyText`,\n`pointSystemText`, `redeemText`, `referralText`."
          }
        },
        "required": [
          "headerSection",
          "historySection",
          "pointSystemSection",
          "redeemSection",
          "FAQSection",
          "referralSection",
          "defaultLanguage",
          "loginUrl",
          "translations"
        ]
      },
      "CartWidgetContent": {
        "type": "object",
        "properties": {
          "cssSelector": {
            "type": "string",
            "description": "Sélecteur CSS de l'élément de la page panier sous lequel insérer le widget."
          },
          "textConnected": {
            "type": "string",
            "description": "Texte du client connecté, dans la langue par défaut de la boutique."
          },
          "textNotConnected": {
            "type": "string",
            "description": "Texte du visiteur non connecté, dans la langue par défaut de la boutique."
          },
          "backgroundColor": {
            "type": "string",
            "description": "Couleur de fond, héritée du branding de la boutique."
          },
          "borderRadius": {
            "type": "number",
            "description": "Arrondi des angles en pixels, hérité du branding de la boutique."
          },
          "iconUrl": {
            "type": "string",
            "description": "URL de l'icône affichée à côté du texte ; chaîne vide si non renseignée."
          },
          "customCss": {
            "type": "string",
            "description": "CSS additionnel injecté par la boutique."
          },
          "defaultLanguage": {
            "type": "string",
            "description": "Code ISO de la langue par défaut de la boutique."
          },
          "loginUrl": {
            "type": "string",
            "description": "URL de la page de connexion de la boutique, dérivée de sa plateforme\n(`store.platform`). Vide quand la plateforme n'en expose pas de dérivable —\nc'est le cas des intégrations `api`, sur mesure par nature. Le widget ne\nrend son état déconnecté cliquable que sur une valeur non vide."
          },
          "translations": {
            "type": "object",
            "additionalProperties": true,
            "description": "Textes indexés par code ISO de langue (`fr`, `en`…). Chaque valeur porte les\nclés de `CartWidgetTranslation` : `textConnected`, `textNotConnected`."
          }
        },
        "required": [
          "cssSelector",
          "textConnected",
          "textNotConnected",
          "backgroundColor",
          "borderRadius",
          "defaultLanguage",
          "loginUrl",
          "translations"
        ]
      },
      "ProductPointsWidgetContent": {
        "type": "object",
        "properties": {
          "cssSelector": {
            "type": "string",
            "description": "Sélecteur CSS de l'élément de la fiche produit sous lequel insérer le widget."
          },
          "textDefault": {
            "type": "string",
            "description": "Texte de la règle par défaut, dans la langue par défaut de la boutique."
          },
          "textProductRule": {
            "type": "string",
            "description": "Texte des règles produit, dans la langue par défaut de la boutique."
          },
          "textCategoryRule": {
            "type": "string",
            "description": "Texte des règles catégorie, dans la langue par défaut de la boutique."
          },
          "backgroundColor": {
            "type": "string",
            "description": "Couleur de fond, héritée du branding de la boutique."
          },
          "borderRadius": {
            "type": "number",
            "description": "Arrondi des angles en pixels, hérité du branding de la boutique."
          },
          "iconUrl": {
            "type": "string",
            "description": "URL de l'icône affichée à côté du texte ; chaîne vide si non renseignée."
          },
          "customCss": {
            "type": "string",
            "description": "CSS additionnel injecté par la boutique."
          },
          "redirectUrl": {
            "type": "string",
            "description": "URL vers laquelle renvoie le widget au clic."
          },
          "defaultLanguage": {
            "type": "string",
            "description": "Code ISO de la langue par défaut de la boutique."
          },
          "translations": {
            "type": "object",
            "additionalProperties": true,
            "description": "Textes indexés par code ISO de langue (`fr`, `en`…). Chaque valeur porte les\nclés de `ProductPointsWidgetTranslation` : `textDefault`, `textProductRule`,\n`textCategoryRule`."
          }
        },
        "required": ["cssSelector", "defaultLanguage", "translations"]
      },
      "DiscountDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "value": {
            "type": "number"
          }
        },
        "required": ["code", "value"]
      },
      "CategoryDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "number"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": ["id", "name", "url"]
      },
      "ProductSectionDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "minimum": 0
          },
          "quantity": {
            "type": "number",
            "minimum": 1
          },
          "externalRef": {
            "type": "number"
          },
          "variantExternalRef": {
            "type": "number"
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CategoryDto"
            }
          }
        },
        "required": [
          "name",
          "amount",
          "quantity",
          "externalRef",
          "variantExternalRef"
        ]
      },
      "OrderSection20260101Dto": {
        "type": "object",
        "properties": {
          "storeAmount": {
            "type": "number",
            "minimum": 0.01
          },
          "purchasedAt": {
            "format": "date-time",
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "externalRef": {
            "type": "number"
          },
          "discounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DiscountDto"
            }
          },
          "products": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductSectionDto"
            }
          },
          "currencyExternalRef": {
            "type": "number"
          }
        },
        "required": [
          "storeAmount",
          "purchasedAt",
          "currency",
          "externalRef",
          "products",
          "currencyExternalRef"
        ]
      },
      "CustomerSectionDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "firstName": {
            "type": "string"
          },
          "birthdate": {
            "format": "date-time",
            "type": "string"
          },
          "externalRef": {
            "type": "number"
          },
          "newsletterSubscribed": {
            "type": "boolean"
          },
          "langExternalRef": {
            "type": "number"
          },
          "langIso": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "firstName",
          "birthdate",
          "externalRef",
          "newsletterSubscribed",
          "langExternalRef",
          "langIso"
        ]
      },
      "Order20260101Dto": {
        "type": "object",
        "properties": {
          "order": {
            "$ref": "#/components/schemas/OrderSection20260101Dto"
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerSectionDto"
          }
        },
        "required": ["order", "customer"]
      },
      "OrderRegisteredResponseDto": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Message de confirmation de la mise en file."
          },
          "storeId": {
            "type": "number",
            "description": "Identifiant interne de la boutique authentifiée."
          }
        },
        "required": ["message", "storeId"]
      },
      "RefundedProductSectionDto": {
        "type": "object",
        "properties": {
          "externalRef": {
            "type": "number",
            "description": "Référence du produit côté plateforme, telle qu'envoyée à l'enregistrement."
          },
          "variantExternalRef": {
            "type": "number",
            "description": "Référence de la déclinaison, `0` si le produit n'en a pas."
          },
          "refundedQuantity": {
            "type": "number",
            "description": "Quantité totale remboursée/retournée pour cette ligne depuis l'origine.",
            "minimum": 0
          },
          "refundedAmount": {
            "type": "number",
            "description": "Montant total remboursé pour cette ligne depuis l'origine (centimes, TTC).",
            "minimum": 0
          }
        },
        "required": ["externalRef", "refundedQuantity", "refundedAmount"]
      },
      "RefundSectionDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "`cancelled` : commande entièrement annulée. `refunded` : remboursement\ntotal. `partial` : remboursement ou retour partiel.",
            "enum": ["cancelled", "refunded", "partial"]
          },
          "externalId": {
            "type": "number",
            "description": "Référence de la commande côté plateforme (PrestaShop : id de commande)."
          },
          "externalReference": {
            "type": "string",
            "description": "Référence lisible de la commande, à titre informatif (journalisation)."
          },
          "customerExternalRef": {
            "type": "number",
            "description": "Référence client côté plateforme, pour scoper la résolution au bon store."
          },
          "refundedAmount": {
            "type": "number",
            "description": "Montant total remboursé sur la commande depuis l'origine (centimes, TTC).",
            "minimum": 0
          },
          "products": {
            "description": "Lignes remboursées. Vide pour une annulation/remboursement total sans détail\nde lignes : chaque ligne est alors remboursée intégralement.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RefundedProductSectionDto"
            }
          },
          "externalStatusRef": {
            "type": "number",
            "description": "Statut brut de la commande côté plateforme, pour la traçabilité (APP-853).\nNe pilote aucun traitement : `type` reste la seule sémantique métier.",
            "minimum": 0
          },
          "externalStatusLabel": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "externalId",
          "customerExternalRef",
          "refundedAmount"
        ]
      },
      "RefundDto": {
        "type": "object",
        "properties": {
          "refund": {
            "$ref": "#/components/schemas/RefundSectionDto"
          }
        },
        "required": ["refund"]
      },
      "OrderRefundedResponseDto": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Message de confirmation de la mise en file."
          },
          "storeId": {
            "type": "number",
            "description": "Identifiant interne de la boutique authentifiée."
          }
        },
        "required": ["message", "storeId"]
      },
      "ProductPointsCalculateResponse": {
        "type": "object",
        "properties": {
          "points": {
            "type": "number",
            "description": "Points que le produit rapporterait au prix demandé."
          },
          "pointName": {
            "type": "string",
            "description": "Nom du point tel que paramétré par la boutique (« point », « étoile »…)."
          },
          "type": {
            "type": "string",
            "description": "Nature de la règle retenue : `PRODUCT`, `CATEGORY` ou `DEFAULT`."
          },
          "id": {
            "type": "number",
            "description": "Identifiant de la règle d'attribution retenue."
          }
        },
        "required": ["points", "pointName", "type", "id"]
      },
      "HistoryEntry": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Motif du mouvement, à traduire côté client.",
            "enum": [
              "order_purchased",
              "manually_registered",
              "mission_accomplished",
              "referral",
              "reward_obtained"
            ]
          },
          "points": {
            "type": "number",
            "description": "Points crédités (positif) ou débités (négatif) par le mouvement."
          },
          "remaining": {
            "type": "number",
            "description": "Points encore disponibles sur ce mouvement, une fois les débits imputés."
          },
          "happenedAt": {
            "type": "string",
            "description": "Date du mouvement (la date d'achat pour une commande), au format ISO 8601."
          },
          "expirationDate": {
            "type": "string",
            "nullable": true,
            "description": "Date d'expiration des points, `null` si la boutique ne les fait pas expirer."
          }
        },
        "required": [
          "reason",
          "points",
          "remaining",
          "happenedAt",
          "expirationDate"
        ]
      },
      "StoreFrontHistoryResponse": {
        "type": "object",
        "properties": {
          "history": {
            "description": "Mouvements de points du client, du plus récent au plus ancien.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HistoryEntry"
            }
          },
          "balance": {
            "type": "number",
            "description": "Solde de points disponible."
          },
          "club": {
            "type": "string",
            "nullable": true,
            "description": "Palier (club) courant du client, `null` s'il n'appartient à aucun palier."
          },
          "clubReviewDate": {
            "type": "string",
            "nullable": true,
            "description": "Date de la prochaine réévaluation du palier, au format ISO 8601."
          }
        },
        "required": ["history", "balance", "club", "clubReviewDate"]
      },
      "RewardByStoreCustomerResponse": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string",
            "description": "Référence de la récompense, à renvoyer à `POST reward/claim` pour l'obtenir."
          },
          "name": {
            "type": "string",
            "description": "Libellé affiché au client."
          },
          "triggerValue": {
            "type": "number",
            "description": "Coût de la récompense, en points."
          },
          "value": {
            "type": "number",
            "description": "Valeur du bon : un montant en centimes ou un pourcentage selon `type`.\nToujours `0` pour `free_shipping` et `clone`, dont la valeur n'appartient pas à\nEnkore — le montant offert d'une livraison n'est connu qu'à la commande, et celui\nd'un bon cloné vit dans le bon source, sur la boutique. Trier ou comparer les\nrécompenses sur ce champ écarterait donc systématiquement ces deux types."
          },
          "type": {
            "type": "string",
            "description": "Type de bon : `amount` (montant fixe), `percentage`, `free_shipping` (livraison\nofferte) ou `clone` (reprise d'un bon existant de la boutique). Les deux derniers\nsont réservés aux boutiques Prestashop.",
            "enum": ["amount", "percentage", "free_shipping", "clone"]
          },
          "isActive": {
            "type": "boolean",
            "description": "`false` lorsque la récompense est désactivée par la boutique."
          },
          "minimumPurchaseAmount": {
            "type": "number",
            "description": "Montant minimum de commande exigé pour utiliser le bon, en centimes."
          },
          "validityPeriod": {
            "type": "number",
            "description": "Durée de validité du bon, en jours, à compter de son obtention."
          }
        },
        "required": [
          "reference",
          "name",
          "triggerValue",
          "value",
          "type",
          "isActive",
          "minimumPurchaseAmount",
          "validityPeriod"
        ]
      },
      "ClaimRewardDto": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          }
        },
        "required": ["reference"]
      },
      "ClaimRewardResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true,
            "description": "Code du bon de réduction généré, `null` si la récompense n'a pas pu être obtenue."
          }
        },
        "required": ["code"]
      },
      "GetRefereeCodeDto": {
        "type": "object",
        "properties": {
          "referral-hash": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": ["referral-hash"]
      },
      "GetRefereeCodeResponse": {
        "type": "object",
        "properties": {
          "match": {
            "type": "boolean",
            "description": "`false` lorsque aucun parrainage ne correspond au hash fourni."
          },
          "code": {
            "type": "string",
            "description": "Code du bon de réduction attribué au filleul."
          },
          "state": {
            "type": "string",
            "description": "État du parrainage (`pending`, `completed`…)."
          },
          "value": {
            "type": "number",
            "description": "Valeur du bon : un montant en centimes ou un pourcentage selon la récompense."
          },
          "minimumPurchaseAmount": {
            "type": "number",
            "description": "Montant minimum de commande exigé pour utiliser le bon, en centimes."
          },
          "validityPeriod": {
            "type": "number",
            "description": "Durée de validité du bon, en jours."
          }
        },
        "required": [
          "match",
          "code",
          "state",
          "value",
          "minimumPurchaseAmount",
          "validityPeriod"
        ]
      },
      "CreateReferralDto": {
        "type": "object",
        "properties": {
          "refereeEmail": {
            "type": "string",
            "format": "email"
          }
        },
        "required": ["refereeEmail"]
      },
      "CreateReferralResponse": {
        "type": "object",
        "properties": {
          "hash": {
            "type": "string",
            "description": "Identifiant du parrainage, à transmettre au filleul pour récupérer son code."
          }
        },
        "required": ["hash"]
      },
      "LegacyError": {
        "type": "object",
        "description": "Corps d’erreur des révisions antérieures à `2026-08-26`. Les erreurs de validation arrivent dans `messages`, une entrée par champ ; les autres refus dans `message`.",
        "properties": {
          "statusCode": {
            "type": "integer",
            "description": "Code HTTP de la réponse."
          },
          "error": {
            "type": "string",
            "description": "Libellé du code HTTP."
          },
          "message": {
            "type": "string",
            "description": "Motif du refus, quand il ne porte pas sur un champ précis."
          },
          "messages": {
            "type": "array",
            "description": "Un élément par champ refusé.",
            "items": {
              "type": "object",
              "properties": {
                "property": {
                  "type": "string"
                },
                "constraint": {
                  "type": "string"
                },
                "defaultMessage": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}
