{
  "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefundDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderRefundedResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/validation-failed` — The request payload is invalid.\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/validation-failed",
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/unauthorized` — Authentication is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/unauthorized"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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 et déclenche le calcul des points de fidélité associés. Le contrat de la commande est celui de la révision `2026-06-18`, servi à toute révision ultérieure ; la révision historique `2026-01-01` reste disponible pour les intégrations existantes via le header `revision`.",
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderRegisteredResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/validation-failed` — The request payload is invalid.\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/validation-failed",
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/unauthorized` — Authentication is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/unauthorized"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "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": "Motifs possibles :\n\n- `https://enkore.io/problems/validation-failed` — The request payload is invalid.\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/validation-failed",
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/not-found"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "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": "Motifs possibles :\n\n- `https://enkore.io/problems/validation-failed` — The request payload is invalid.\n- `https://enkore.io/problems/referral-customer-already-exists` — This email address already belongs to a customer account.\n- `https://enkore.io/problems/referral-already-pending` — This email address has already been invited and its referral is pending.\n- `https://enkore.io/problems/referral-already-completed` — This email address has already been referred.\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/validation-failed",
                            "https://enkore.io/problems/referral-customer-already-exists",
                            "https://enkore.io/problems/referral-already-pending",
                            "https://enkore.io/problems/referral-already-completed",
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/unauthorized` — Authentication is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/unauthorized"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "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": "Motifs possibles :\n\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/unauthorized` — Authentication is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/unauthorized"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "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": "Motifs possibles :\n\n- `https://enkore.io/problems/validation-failed` — The request payload is invalid.\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/validation-failed",
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/unauthorized` — Authentication is missing or invalid.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/unauthorized"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "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\nMotifs possibles :\n\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string",
                      "nullable": true,
                      "description": "Code du bon obtenu, `null` si l’échange est refusé."
                    }
                  }
                }
              },
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/not-found"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "422": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/platform-credentials-rejected` — The store platform rejected the credentials registered for this store.\n- `https://enkore.io/problems/platform-resource-not-found` — The store platform does not expose the resource this operation needs.\n- `https://enkore.io/problems/platform-request-rejected` — The store platform refused the operation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/platform-credentials-rejected",
                            "https://enkore.io/problems/platform-resource-not-found",
                            "https://enkore.io/problems/platform-request-rejected"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "502": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/platform-unavailable` — The store platform did not answer, please try again.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/platform-unavailable"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "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": "Motifs possibles :\n\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/not-found"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRefereeCodeDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetRefereeCodeResponse"
                }
              }
            }
          },
          "400": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/validation-failed` — The request payload is invalid.\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/validation-failed",
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/not-found"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "422": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/platform-credentials-rejected` — The store platform rejected the credentials registered for this store.\n- `https://enkore.io/problems/platform-resource-not-found` — The store platform does not expose the resource this operation needs.\n- `https://enkore.io/problems/platform-request-rejected` — The store platform refused the operation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/platform-credentials-rejected",
                            "https://enkore.io/problems/platform-resource-not-found",
                            "https://enkore.io/problems/platform-request-rejected"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "502": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/platform-unavailable` — The store platform did not answer, please try again.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/platform-unavailable"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CartWidgetContent"
                }
              }
            }
          },
          "400": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/not-found"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductPointsWidgetContent"
                }
              }
            }
          },
          "400": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/not-found"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
            "schema": {
              "type": "string",
              "enum": ["2026-08-26"],
              "default": "2026-08-26"
            }
          },
          {
            "name": "domain",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PresentationWidgetContent"
                }
              }
            }
          },
          "400": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/invalid-revision-header",
                            "https://enkore.io/problems/unknown-api-revision"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": ["https://enkore.io/problems/not-found"]
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Motifs possibles :\n\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ProblemDetails"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "https://enkore.io/problems/internal-server-error"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        },
        "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-08-26.",
    "version": "2026-08-26",
    "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": {
            "description": "Cadrage de l'image : `cover` (rognée, hauteur fixe) ou `ratio` (ratio de l'image).",
            "enum": ["cover", "ratio"],
            "type": "string"
          },
          "mobileLayout": {
            "description": "Disposition mobile : `overlay` (texte sur l'image) ou `stacked` (texte sous l'image).",
            "enum": ["overlay", "stacked"],
            "type": "string"
          },
          "contentPosition": {
            "description": "Position du bloc de texte dans la bannière.",
            "enum": ["center", "left", "right"],
            "type": "string"
          },
          "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": {
            "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"
            ],
            "type": "string"
          },
          "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": {
            "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"
            ],
            "type": "string"
          },
          "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"
        ]
      },
      "OrderSectionDto": {
        "type": "object",
        "properties": {
          "storeAmount": {
            "type": "number",
            "minimum": 0.01
          },
          "purchasedAt": {
            "format": "date-time",
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "externalId": {
            "type": "number"
          },
          "externalReference": {
            "type": "string"
          },
          "discounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DiscountDto"
            }
          },
          "products": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductSectionDto"
            }
          },
          "currencyExternalRef": {
            "type": "number"
          },
          "externalStatusRef": {
            "type": "number",
            "minimum": 0
          },
          "externalStatusLabel": {
            "type": "string"
          }
        },
        "required": [
          "storeAmount",
          "purchasedAt",
          "currency",
          "externalId",
          "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"
        ]
      },
      "OrderDto": {
        "type": "object",
        "properties": {
          "order": {
            "$ref": "#/components/schemas/OrderSectionDto"
          },
          "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": {
            "description": "`cancelled` : commande entièrement annulée. `refunded` : remboursement\ntotal. `partial` : remboursement ou retour partiel.",
            "enum": ["cancelled", "refunded", "partial"],
            "type": "string"
          },
          "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": {
            "description": "Motif du mouvement, à traduire côté client.",
            "enum": [
              "order_purchased",
              "manually_registered",
              "mission_accomplished",
              "referral",
              "reward_obtained"
            ],
            "type": "string"
          },
          "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": {
            "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"],
            "type": "string"
          },
          "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"]
      },
      "ProblemDetails": {
        "type": "object",
        "description": "Corps d’erreur au format [RFC 9457](https://datatracker.ietf.org/doc/html/rfc9457), servi avec le type de média `application/problem+json`.",
        "required": ["type", "title", "status", "instance"],
        "properties": {
          "type": {
            "type": "string",
            "description": "URI stable du motif de refus. **C’est la valeur sur laquelle brancher un traitement** : elle ne change jamais, ni dans sa forme ni dans son sens. L’URI n’est pas déréférençable (RFC 9457 §3.1.1).\n\n- `https://enkore.io/problems/bad-request` — The request could not be accepted.\n- `https://enkore.io/problems/unauthorized` — Authentication is missing or invalid.\n- `https://enkore.io/problems/forbidden` — The caller is not allowed to perform this operation.\n- `https://enkore.io/problems/not-found` — The requested resource does not exist.\n- `https://enkore.io/problems/unprocessable-entity` — The request is well-formed but could not be processed.\n- `https://enkore.io/problems/internal-server-error` — The request could not be completed.\n- `https://enkore.io/problems/validation-failed` — The request payload is invalid.\n- `https://enkore.io/problems/invalid-revision-header` — The 'revision' header is not a valid date.\n- `https://enkore.io/problems/unknown-api-revision` — The requested API revision does not exist.\n- `https://enkore.io/problems/platform-credentials-rejected` — The store platform rejected the credentials registered for this store.\n- `https://enkore.io/problems/platform-resource-not-found` — The store platform does not expose the resource this operation needs.\n- `https://enkore.io/problems/platform-request-rejected` — The store platform refused the operation.\n- `https://enkore.io/problems/platform-unavailable` — The store platform did not answer, please try again.\n- `https://enkore.io/problems/manager-invitation-failed` — The manager invitation could not be sent, please try again.\n- `https://enkore.io/problems/unsupported-store-platform` — The selected e-commerce platform is not supported.\n- `https://enkore.io/problems/store-unreachable` — The store could not be reached at the given domain.\n- `https://enkore.io/problems/invalid-prestashop-credentials` — The PrestaShop webservice key is missing or lacks the required permissions.\n- `https://enkore.io/problems/store-languages-not-synced` — The store languages must be synchronised before importing categories.\n- `https://enkore.io/problems/referral-customer-already-exists` — This email address already belongs to a customer account.\n- `https://enkore.io/problems/referral-already-pending` — This email address has already been invited and its referral is pending.\n- `https://enkore.io/problems/referral-already-completed` — This email address has already been referred.\n- `https://enkore.io/problems/voucher-type-prestashop-only` — This voucher type is only available on PrestaShop.\n- `https://enkore.io/problems/clone-webservice-key-missing` — No PrestaShop webservice key is registered for this store.\n- `https://enkore.io/problems/clone-store-unreachable` — The store did not answer the voucher cloning capability check.\n- `https://enkore.io/problems/clone-resource-unavailable` — The 'enkore_cart_rule_clones' webservice resource is not reachable.\n- `https://enkore.io/problems/clone-resource-post-forbidden` — The PrestaShop webservice key is not allowed to POST on 'enkore_cart_rule_clones'.\n- `https://enkore.io/problems/validation/required` — The field is required.\n- `https://enkore.io/problems/validation/wrong-type` — The field is not of the expected type.\n- `https://enkore.io/problems/validation/out-of-range` — The value is outside the accepted range.\n- `https://enkore.io/problems/validation/wrong-length` — The value does not have an accepted length.\n- `https://enkore.io/problems/validation/not-allowed` — The value is not one of the accepted values.\n- `https://enkore.io/problems/validation/malformed` — The value does not have the expected format.\n- `https://enkore.io/problems/validation/invalid` — The value was refused.",
            "enum": [
              "https://enkore.io/problems/bad-request",
              "https://enkore.io/problems/unauthorized",
              "https://enkore.io/problems/forbidden",
              "https://enkore.io/problems/not-found",
              "https://enkore.io/problems/unprocessable-entity",
              "https://enkore.io/problems/internal-server-error",
              "https://enkore.io/problems/validation-failed",
              "https://enkore.io/problems/invalid-revision-header",
              "https://enkore.io/problems/unknown-api-revision",
              "https://enkore.io/problems/platform-credentials-rejected",
              "https://enkore.io/problems/platform-resource-not-found",
              "https://enkore.io/problems/platform-request-rejected",
              "https://enkore.io/problems/platform-unavailable",
              "https://enkore.io/problems/manager-invitation-failed",
              "https://enkore.io/problems/unsupported-store-platform",
              "https://enkore.io/problems/store-unreachable",
              "https://enkore.io/problems/invalid-prestashop-credentials",
              "https://enkore.io/problems/store-languages-not-synced",
              "https://enkore.io/problems/referral-customer-already-exists",
              "https://enkore.io/problems/referral-already-pending",
              "https://enkore.io/problems/referral-already-completed",
              "https://enkore.io/problems/voucher-type-prestashop-only",
              "https://enkore.io/problems/clone-webservice-key-missing",
              "https://enkore.io/problems/clone-store-unreachable",
              "https://enkore.io/problems/clone-resource-unavailable",
              "https://enkore.io/problems/clone-resource-post-forbidden",
              "https://enkore.io/problems/validation/required",
              "https://enkore.io/problems/validation/wrong-type",
              "https://enkore.io/problems/validation/out-of-range",
              "https://enkore.io/problems/validation/wrong-length",
              "https://enkore.io/problems/validation/not-allowed",
              "https://enkore.io/problems/validation/malformed",
              "https://enkore.io/problems/validation/invalid"
            ]
          },
          "title": {
            "type": "string",
            "description": "Résumé court et stable du motif, en anglais. Ne dépend que de `type`, et n’est pas destiné à être affiché à un utilisateur final : la phrase à montrer se choisit côté client, à partir de `type`."
          },
          "status": {
            "type": "integer",
            "description": "Code HTTP de la réponse, redondant avec elle — la RFC l’exige."
          },
          "detail": {
            "type": "string",
            "description": "Ce qui a échoué sur cette requête-ci, quand l’API a mieux à dire que `title`. En anglais, à destination du développeur qui intègre."
          },
          "instance": {
            "type": "string",
            "description": "Chemin appelé, identifiant l’occurrence du refus."
          },
          "errors": {
            "type": "array",
            "description": "Une entrée par champ refusé. Présent sur `validation-failed` uniquement.",
            "items": {
              "$ref": "#/components/schemas/ProblemValidationError"
            }
          }
        }
      },
      "ProblemValidationError": {
        "type": "object",
        "description": "Champ refusé par la validation du corps envoyé. Les paramètres du motif (`expectedType`, `maxLength`, `format`, `minimum`…) sont ajoutés à la racine de l’entrée et empruntent le vocabulaire de JSON Schema.",
        "required": ["type", "pointer", "detail"],
        "properties": {
          "type": {
            "type": "string",
            "description": "Nature de la règle violée.\n\n- `https://enkore.io/problems/validation/required` — The field is required.\n- `https://enkore.io/problems/validation/wrong-type` — The field is not of the expected type.\n- `https://enkore.io/problems/validation/out-of-range` — The value is outside the accepted range.\n- `https://enkore.io/problems/validation/wrong-length` — The value does not have an accepted length.\n- `https://enkore.io/problems/validation/not-allowed` — The value is not one of the accepted values.\n- `https://enkore.io/problems/validation/malformed` — The value does not have the expected format.\n- `https://enkore.io/problems/validation/invalid` — The value was refused.\n\nUn motif métier déclaré sur le champ prend la place de ces sept : le `type` décrit alors le refus, et non la contrainte qui l’a détecté."
          },
          "pointer": {
            "type": "string",
            "description": "JSON Pointer ([RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901)) désignant le champ fautif dans le corps envoyé, par exemple `/order/products/0/amount`."
          },
          "detail": {
            "type": "string",
            "description": "Phrase anglaise produite par le validateur, à destination du développeur."
          }
        }
      }
    }
  }
}
