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.
Transports
Section intitulée « Transports »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 pagewidget.setContext({ date: "2026-09-03", partySize: 4 });Priorité
Section intitulée « Priorité »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.
Les valeurs
Section intitulée « Les valeurs »| 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-*.
Une plage horaire plutôt qu’un service
Section intitulée « Une plage horaire plutôt qu’un service »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:30Les 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 :
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: "none"
Section intitulée « sectionKey: "none" »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 sallenull 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=anyLes 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.
Les langues
Section intitulée « Les langues »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.
Fournissez locale sur chaque surface où vous connaissez la langue du client.
C’est la seule indication dont l’absence se remarque immédiatement.
Confiance
Section intitulée « Confiance »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.
Contraindre une valeur
Section intitulée « Contraindre une valeur »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.