Aller au contenu

Transmettre le contexte

Le contexte pré-positionne le parcours de réservation. Le widget s’ouvre sur la première valeur non fournie, plutôt que sur la première étape.

Sept valeurs atteignent le widget par trois transports.

<!-- 1. Balise de script — pour un CMS, où il n'y a aucun JavaScript à écrire -->
<script src="https://app.useservice.app/widget/widget.js"
data-slug="chez-marie" data-date="2026-09-03" data-party-size="4" async></script>
2. URL — pour l'e-mail, le SMS, les QR codes, partout où votre site n'a aucun JavaScript
https://book.useservice.app/r/chez-marie?date=2026-09-03&party=4
// 3. JavaScript — pour un contexte qui change après le chargement de la page
widget.setContext({ date: "2026-09-03", partySize: 4 });

data-*, puis l’URL, puis setContext(). La dernière source à fournir une valeur l’emporte.

setContext() a la priorité la plus haute parce que le contexte change après le chargement : un client peut choisir ses dates dans le moteur de recherche de votre site avant d’ouvrir le widget.

La fusion se fait champ par champ. Une source qui ne fournit que partySize n’efface pas une date fournie auparavant.

Indication data-* URL Format
date data-date date AAAA-MM-JJ
time data-time time HH:MM, sur 24 heures
partySize data-party-size party Entier, 1 à 100
sectionKey data-section-key section Clé de groupe de salle, ou none
timeFrom data-time-from from HH:MM — créneau le plus tôt proposé
timeTo data-time-to to HH:MM — créneau le plus tard proposé
shiftId data-shift-id shift Entier — restreint le parcours à un service
locale data-locale locale L’une des 11 langues client
guestNotes data-guest-notes notes Texte libre, jusqu’à 2 000 caractères

Les noms d’URL sont courts et faciles à taper à dessein : ils finissent dans des QR codes imprimés et des liens marketing, et ne reprennent donc volontairement pas l’orthographe des data-*.

timeFrom et timeTo ne proposent que les créneaux compris entre les deux, bornes incluses. C’est l’alternative portable à shiftId : un identifiant de service diffère d’un restaurant à l’autre, si bien qu’un groupe appliquant une même intégration à dix sites doit faire dix lectures, alors que 19:00–22:30 signifie la même chose partout.

https://book.useservice.app/r/chez-marie?from=19:00&to=22:30

Les deux bornes sont nécessaires. Une borne seule est refusée plutôt que lue comme ouverte : vous avez écrit une plage, et une demi-plage appliquée en silence est pire que pas de plage du tout.

Elles se combinent avec shiftId au lieu de le remplacer, et chacune restreint indépendamment : un service et une plage donnent les créneaux qui satisfont les deux.

Trouver une clé de salle ou un identifiant de service

Section intitulée « Trouver une clé de salle ou un identifiant de service »

Les deux sont propres à chaque restaurant, et proviennent du même appel non authentifié que le widget effectue lui-même à l’ouverture :

Fenêtre de terminal
curl "https://app.useservice.app/api/v1/public/restaurants/chez-marie?include=section_groups,availability"

Les clés de salle figurent dans section_groups. Utilisez key — name est localisé et change, key non :

{ "section_groups": { "data": [
{ "key": "31", "name": "Terrasse", "area_type": "outdoor", "bookable_online": true }
] } }

Les identifiants de service figurent sur chaque jour d’availability, car les services d’un restaurant varient selon le jour :

{ "availability": { "months": { "2026-09": { "days": [
{ "date": "2026-09-03", "shifts": [ { "id": 1, "name": "Déjeuner", "start_time": "12:00", "end_time": "14:30" } ] }
] } } } }

Lisez-les une fois et mettez-les en cache par restaurant ; ils ne changent que lorsque le restaurant reconfigure son plan de salle ou ses services. Il n’existe pas d’endpoint de consultation distinct : c’est la charge utile même que le widget affiche, donc une valeur visible ici est une valeur que le tunnel acceptera.

Sur plusieurs restaurants, ne présumez pas que les identifiants coïncident. « Terrasse » correspond à une key différente dans chaque restaurant, et « Déjeuner » à un shift_id différent : un groupe qui applique une même intégration à dix sites doit faire une lecture par site.

sectionKey est le seul champ dont l’absence est elle-même une valeur. « Aucune préférence de salle, et le client ne peut pas la changer » se distingue de « aucune indication sur la salle ».

Les deux sont indiscernables sur le fil : après un nettoyage et un encodeur JSON, une clé absente, null et "" sont identiques. Le premier sens voyage donc sous la forme de la chaîne "none" :

widget.setContext({ sectionKey: "none" }); // aucune préférence, et c'est verrouillé
widget.setContext({ sectionKey: null }); // ne dit rien sur la salle

null est lu comme « aucune indication », et le sélecteur de salle est affiché. Envoyer null à la place de "none" produit donc le résultat inverse de celui recherché.

"none" est sans ambiguïté comme littéral : les clés de salle sont des identifiants convertis en chaîne, aucun restaurant ne peut donc porter ce nom de salle.

En tant qu’indice, "any" est également accepté (insensible à la casse) et signifie la même chose que null — « aucune indication sur le placement », sélecteur affiché. Il existe parce qu’any se lit naturellement dans une URL saisie à la main :

https://book.useservice.app/r/chez-marie?section=any

Les deux mots ne sont donc pas synonymes, et la différence tient au niveau de confiance, pas au placement :

Valeur Où Signification
"any" indice uniquement Aucune indication — le client choisit, sélecteur affiché
null indice uniquement Identique à "any"
"none" jeton signé Aucune préférence, et épinglé — sélecteur masqué

Seul un jeton signé peut épingler le placement ; "any" dans une URL ne le peut pas, car une URL que n’importe qui peut modifier n’est pas une contrainte.

locale choisit la langue dans laquelle le parcours démarre. Le widget en embarque onze :

Code Langue Code Langue Code Langue
fr Français it Italiano sv Svenska
en English nl Nederlands no Norsk
de Deutsch pt Português fi Suomi
es Español da Dansk

La correspondance est exacte. Les indicatifs régionaux et les autres orthographes ne sont pas reconnus : fr-CA, en-GB et FR sont ignorés comme toute autre valeur qui ne s’analyse pas. Envoyez le code seul.

Chaque restaurant choisit lesquelles des onze il propose à ses clients. Le widget affiche un sélecteur de langue lorsqu’un restaurant en propose plus d’une, et le choix du client est conservé par restaurant et l’emporte sur la valeur que vous fournissez — voir liens profonds.

Omettre locale ne revient pas à ne rien transmettre d’utile. Le widget la résout, par ordre de priorité :

  1. Le choix antérieur du client sur ce restaurant, fait depuis le sélecteur.
  2. Votre locale, si vous en avez envoyé une.
  3. La langue du navigateur du client — mais seulement si le restaurant la propose. Un client germanophone lit le parcours en allemand dans un restaurant qui sert l’allemand ; dans un restaurant qui ne le sert pas, son navigateur est ignoré.
  4. La langue principale du restaurant.

Les étapes 3 et 4 sont ce qui fait de l’omission une valeur par défaut raisonnable plutôt qu’une lacune : une page qui ignore la langue de son lecteur ne lui affichera pas pour autant une langue que le restaurant n’a jamais activée.

Envoyez locale lorsque votre page sait réellement mieux que le navigateur — une version /de/ de votre site, ou un client dont vous connaissez la langue. En envoyer une simplement devinée est pire que de n’en envoyer aucune, car elle l’emporte sur le signal du navigateur qui, lui, aurait été juste.

Chaque valeur de cette page est une indication. Les indications sont falsifiables et le client peut toutes les modifier : le widget les traite donc comme une saisie du client.

L’identité n’est pas une indication et ne voyage pas ainsi. parseUrlHints n’a aucun nom d’URL pour un nom, un e-mail ou un téléphone : des champs d’identité ne peuvent donc pas apparaître dans une URL par accident. L’identité passe par un jeton signé — voir identifier le client.

Une valeur qui ne s’analyse pas est ignorée. Elle n’est jamais partiellement appliquée ni fatale : ?date=n-importe-quoi ouvre le calendrier ordinaire.

Les indications ne contraignent pas : le widget affiche la valeur et le client la modifie librement. Pour l’afficher comme fixe, verrouillez-la — depuis les trois mêmes transports :

<script … data-locked="date" data-lock-reason="Bon cadeau BC-4471" async></script>

Un verrou posé ainsi est affiché, pas appliqué. Le serveur accepte une réservation qui le contredit, car une chaîne de requête ou un attribut peut être écrit par n’importe qui et il n’a aucun moyen de distinguer le vôtre du sien. Pour une valeur qui doit réellement tenir, placez le champ dans locked à l’intérieur du jeton signé, que le serveur applique bel et bien.

Les deux sont traités dans Verrouiller des champs.