{
  "openapi": "3.1.0",
  "info": {
    "title": "Tekshelf · API du tenant",
    "version": "0.5.0-draft",
    "description": "Documentation en lecture seule des appels pour suivre les Shelfy dans No Waste. Les schémas détaillés manquants sont signalés. Les choix encore ouverts sont regroupés dans le guide « Points à confirmer »."
  },
  "servers": [
    {
      "url": "https://tenant.example.invalid",
      "description": "Domaine fictif : remplacer par l’origine fournie pour chaque tenant."
    }
  ],
  "tags": [
    {
      "name": "Shelfy",
      "description": "Suivre l’état et le remplissage des Shelfy."
    },
    {
      "name": "Meubles",
      "description": "Lire les meubles et la vue enrichie."
    },
    {
      "name": "Produits",
      "description": "Rechercher et consulter les fiches produits."
    },
    {
      "name": "Dispositifs",
      "description": "Consulter le dispositif associé au bac."
    },
    {
      "name": "Événements",
      "description": "Consulter le journal d’événements (hors mesures des Shelfy)."
    }
  ],
  "paths": {
    "/api/promo-bins": {
      "get": {
        "tags": [
          "Shelfy"
        ],
        "summary": "Lister les bacs d'un magasin",
        "description": "Pour chaque bac : objet `shelfy` (identité, produits, indicateur de remplissage), `acquisition` et `weight`. Réponse `{items,total}`.",
        "parameters": [
          {
            "name": "storeId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bacs du magasin."
          },
          "400": {
            "description": "Paramètre invalide (INVALID_QUERY)."
          },
          "403": {
            "description": "Droit manquant ou bac d'un autre magasin (réponse identique)."
          },
          "404": {
            "description": "Bac introuvable."
          }
        }
      }
    },
    "/api/promo-bins/{deviceId}": {
      "get": {
        "tags": [
          "Shelfy"
        ],
        "summary": "Consulter un bac",
        "description": "État courant d'un bac : identité, produits, indicateur de remplissage.",
        "parameters": [
          {
            "name": "deviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bac."
          },
          "400": {
            "description": "Paramètre invalide (INVALID_QUERY)."
          },
          "403": {
            "description": "Droit manquant ou bac d'un autre magasin (réponse identique)."
          },
          "404": {
            "description": "Bac introuvable."
          }
        }
      }
    },
    "/api/promo-bins/by-serial/{serial}": {
      "get": {
        "tags": [
          "Shelfy"
        ],
        "summary": "Retrouver un bac par numéro de série",
        "description": "Même objet que la lecture par identifiant.",
        "parameters": [
          {
            "name": "serial",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bac."
          },
          "400": {
            "description": "Paramètre invalide (INVALID_QUERY)."
          },
          "403": {
            "description": "Droit manquant ou bac d'un autre magasin (réponse identique)."
          },
          "404": {
            "description": "Bac introuvable."
          }
        }
      }
    },
    "/api/promo-bins/{deviceId}/fill-history": {
      "get": {
        "tags": [
          "Shelfy"
        ],
        "summary": "Historique de remplissage",
        "description": "Un point par tranche (15 min jusqu'à 48 h, 1 h jusqu'à 192 h, 4 h au-delà ; 30 jours au plus). Donner `hours` ou `days`, jamais les deux. Chaque point : `at`, `weightG`, `percent` (null avant la référence 100 %), `restock`.",
        "parameters": [
          {
            "name": "deviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "hours",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 12,
              "maximum": 720
            }
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 7
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Historique paginé."
          },
          "400": {
            "description": "Paramètre invalide (INVALID_QUERY)."
          },
          "403": {
            "description": "Droit manquant ou bac d'un autre magasin (réponse identique)."
          },
          "404": {
            "description": "Bac introuvable."
          }
        }
      }
    },
    "/api/promo-bins/{deviceId}/acquisition": {
      "get": {
        "tags": [
          "Shelfy"
        ],
        "summary": "Fraîcheur des mesures",
        "description": "`lastAt`, `lastContactAt`, `nextAt`, `nextEstimated`, `intervalS`.",
        "parameters": [
          {
            "name": "deviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Acquisition."
          },
          "400": {
            "description": "Paramètre invalide (INVALID_QUERY)."
          },
          "403": {
            "description": "Droit manquant ou bac d'un autre magasin (réponse identique)."
          },
          "404": {
            "description": "Bac introuvable."
          }
        }
      }
    },
    "/api/furnitures": {
      "get": {
        "tags": [
          "Meubles"
        ],
        "summary": "Lister les meubles d’une pharmacie",
        "description": "Liste les meubles du magasin. Les Shelfy portent le type `promo_bin`. Utiliser `storeId` pour cibler la pharmacie et `zoneId` pour limiter la liste à une zone.",
        "operationId": "get_api_furnitures",
        "responses": {
          "200": {
            "description": "Succès.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "example": {},
                        "additionalProperties": true,
                        "description": "Schéma détaillé non renseigné."
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    }
                  },
                  "additionalProperties": true,
                  "description": "Liste paginée. Le schéma détaillé des éléments reste à renseigner.",
                  "example": {
                    "items": [],
                    "total": 0,
                    "page": 1,
                    "limit": 20
                  }
                }
              }
            }
          }
        },
        "x-allowed-use": "Gestion des Shelfy, selon les droits du partenaire.",
        "parameters": [
          {
            "name": "storeId",
            "in": "query",
            "required": false,
            "description": "Identifiant du magasin autorisé.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "zoneId",
            "in": "query",
            "required": false,
            "description": "Filtre optionnel de zone.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Numéro de page, à partir de 1.",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Nombre d’éléments par page.",
            "schema": {
              "type": "integer",
              "default": 100,
              "minimum": 1,
              "maximum": 100
            }
          }
        ]
      }
    },
    "/api/furnitures/map": {
      "get": {
        "tags": [
          "Meubles"
        ],
        "summary": "Consulter la vue enrichie des bacs",
        "description": "Vue enrichie des meubles, niveaux et données de stock : `currentCount`, `status`, `lastUpdateAt`, `fillPercent` et `fillStatus`. Certains comptages absents sont convertis en zéro dans cette vue : vérifier la fraîcheur et la validité avant de présenter une rupture. Le schéma détaillé reste à renseigner.",
        "operationId": "get_api_furnitures_map",
        "responses": {
          "200": {
            "description": "Succès.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "example": {},
                    "additionalProperties": true,
                    "description": "Schéma détaillé non renseigné."
                  }
                }
              }
            }
          },
          "400": {
            "description": "Erreur de la requête.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    }
                  },
                  "additionalProperties": true,
                  "example": {
                    "error": "Message d’erreur (exemple fictif)"
                  }
                }
              }
            }
          }
        },
        "x-allowed-use": "Gestion des Shelfy, selon les droits du partenaire.",
        "parameters": [
          {
            "name": "storeId",
            "in": "query",
            "required": true,
            "description": "Identifiant du magasin autorisé.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/furnitures/{furnitureId}": {
      "get": {
        "tags": [
          "Meubles"
        ],
        "summary": "Consulter le détail d’un bac",
        "description": "Retourne le meuble et ses niveaux. Un Shelfy est un meuble de type `promo_bin`.",
        "operationId": "get_api_furnitures_furnitureId",
        "responses": {
          "200": {
            "description": "Succès.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "example": {},
                  "additionalProperties": true,
                  "description": "Schéma détaillé non renseigné."
                }
              }
            }
          },
          "404": {
            "description": "Erreur de la requête.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    }
                  },
                  "additionalProperties": true,
                  "example": {
                    "error": "Message d’erreur (exemple fictif)"
                  }
                }
              }
            }
          }
        },
        "x-allowed-use": "Gestion des Shelfy, selon les droits du partenaire.",
        "parameters": [
          {
            "name": "furnitureId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/products": {
      "get": {
        "tags": [
          "Produits"
        ],
        "summary": "Rechercher les produits",
        "description": "Recherche les produits du tenant. `ean` recherche un code exact dans EAN, master CIP et CIP13 ; il prend la priorité sur `search`. La réponse est paginée.",
        "operationId": "get_api_products",
        "responses": {
          "200": {
            "description": "Succès.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "example": {},
                        "additionalProperties": true,
                        "description": "Schéma détaillé non renseigné."
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    }
                  },
                  "additionalProperties": true,
                  "description": "Liste paginée. Le schéma détaillé des éléments reste à renseigner.",
                  "example": {
                    "items": [],
                    "total": 0,
                    "page": 1,
                    "limit": 20
                  }
                }
              }
            }
          }
        },
        "x-allowed-use": "Gestion des Shelfy, selon les droits du partenaire.",
        "parameters": [
          {
            "name": "ean",
            "in": "query",
            "required": false,
            "description": "Code exact EAN ou CIP.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Recherche textuelle.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "section",
            "in": "query",
            "required": false,
            "description": "Filtre de section.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Numéro de page, à partir de 1.",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Nombre d’éléments par page ; maximum 100.",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          }
        ]
      }
    },
    "/api/products/{productId}": {
      "get": {
        "tags": [
          "Produits"
        ],
        "summary": "Consulter un produit",
        "description": "Retourne la fiche produit identifiée par `productId`.",
        "operationId": "get_api_products_productId",
        "responses": {
          "200": {
            "description": "Succès.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "example": {},
                  "additionalProperties": true,
                  "description": "Schéma détaillé non renseigné."
                }
              }
            }
          },
          "404": {
            "description": "Erreur de la requête.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    }
                  },
                  "additionalProperties": true,
                  "example": {
                    "error": "Message d’erreur (exemple fictif)"
                  }
                }
              }
            }
          }
        },
        "x-allowed-use": "Gestion des Shelfy, selon les droits du partenaire.",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/devices/{deviceId}": {
      "get": {
        "tags": [
          "Dispositifs"
        ],
        "summary": "Consulter le dispositif peseur",
        "description": "Retourne le dispositif peseur associé au bac. Le dispositif est distinct du meuble qui représente le bac dans le magasin.",
        "operationId": "get_api_devices_deviceId",
        "responses": {
          "200": {
            "description": "Succès.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "example": {},
                  "additionalProperties": true,
                  "description": "Schéma détaillé non renseigné."
                }
              }
            }
          },
          "404": {
            "description": "Erreur de la requête.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer"
                    }
                  },
                  "additionalProperties": true,
                  "example": {
                    "error": "Message d’erreur (exemple fictif)"
                  }
                }
              }
            }
          }
        },
        "x-allowed-use": "Gestion des Shelfy, selon les droits du partenaire.",
        "parameters": [
          {
            "name": "deviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/events": {
      "get": {
        "tags": [
          "Événements"
        ],
        "summary": "Récupérer l’historique",
        "description": "Historique paginé, filtrable par magasin, dispositif et produit. Avec `from` et `to`, le début est inclus et la fin exclue. Une période nommée prend la priorité sur ces dates. `excludePositive=true` retire les événements dont `differenceProduct > 0` ; ce n’est pas un filtre de ventes. La reprise de synchronisation doit gérer les événements arrivant pendant la pagination.",
        "operationId": "get_api_events",
        "responses": {
          "200": {
            "description": "Succès.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "example": {},
                        "additionalProperties": true,
                        "description": "Schéma détaillé non renseigné."
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    }
                  },
                  "additionalProperties": true,
                  "description": "Liste paginée. Le schéma détaillé des éléments reste à renseigner.",
                  "example": {
                    "items": [],
                    "total": 0,
                    "page": 1,
                    "limit": 20
                  }
                }
              }
            }
          }
        },
        "x-allowed-use": "Gestion des Shelfy, selon les droits du partenaire.",
        "parameters": [
          {
            "name": "storeId",
            "in": "query",
            "required": false,
            "description": "Magasin autorisé.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "required": false,
            "description": "Dispositif concerné.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "productId",
            "in": "query",
            "required": false,
            "description": "Produit concerné.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "scaleIndex",
            "in": "query",
            "required": false,
            "description": "Index de balance.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Type d’événement ; valeurs à valider.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Début inclus. Utiliser une date avec fuseau explicite.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fin exclue. Utiliser une date avec fuseau explicite.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Période prédéfinie ; ne pas combiner avec from/to.",
            "schema": {
              "type": "string",
              "enum": [
                "today",
                "yesterday",
                "last7Days",
                "last30Days",
                "thisWeek",
                "thisMonth"
              ]
            }
          },
          {
            "name": "excludePositive",
            "in": "query",
            "required": false,
            "description": "Exclure les mouvements strictement positifs.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Champ de tri.",
            "schema": {
              "type": "string",
              "default": "createdAt",
              "enum": [
                "createdAt",
                "type",
                "differenceProduct"
              ]
            }
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "description": "Ordre du tri.",
            "schema": {
              "type": "string",
              "default": "DESC",
              "enum": [
                "ASC",
                "DESC"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Numéro de page, à partir de 1.",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Nombre d’éléments par page ; maximum 100.",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          }
        ]
      }
    }
  },
  "x-draft": true,
  "x-authentication-status": "Non spécifié : aucun mécanisme d’authentification n’est garanti par cet export."
}