Skip to main content

Centre de préférences : la page publique d’opt-in/opt-out

Original anglais : Preference center: the public opt-in/opt-out page.
Le centre de préférences est une page publique où un contact gère lui-même ses opt-ins de canaux, ses sujets d’abonnement, sa fréquence de messages et (si vous l’activez) dépose une demande d’effacement de données — sans compte, sans connexion. Chaque contact y accède par un lien signé : l’URL porte un jeton HMAC-SHA256 (v1.<payload>.<signature>) qui expire après 30 jours, si bien que la page reste en libre-service tout en étant limitée à exactement un contact dans exactement une organisation. La surface résumée des endpoints vit aussi dans Send Gates ; ce guide est le parcours complet : chaque champ de configuration, où placer le lien, ce que renvoie l’API de la page publique et quelles surfaces de conformité un opt-out ou un opt-in écrit. Tous les endpoints ci-dessous sont ancrés sur https://api.orbit.devotel.io/api/v1/compliance.
Le centre de préférences est un contrôle détenu par le tenant : vous choisissez les canaux, les sujets et la marque, et votre organisation conserve la preuve du consentement. Orbit exploite la plateforme ; la décision de consentement appartient au contact. Ce guide n’est pas un avis juridique — confirmez vos obligations auprès de votre conseil.

1. Configurer une fois : POST/GET /preference-center

Définissez la configuration avec POST /preference-center (clé API owner/admin). L’endpoint fait un upsert de la configuration dans les paramètres de votre organisation et renvoie l’objet enregistré — relancez-le pour mettre à jour. GET /preference-center relit la configuration courante ; avant configuration, il renvoie enabled: false avec un message d’indice.

Champs de configuration

Chaque champ est validé côté serveur — un POST rejeté renvoie 422 avec des problèmes par champ (field, message) pour savoir lequel a échoué.

Sujets d’abonnement

Un sujet est un groupe nommé — Newsletter, Product Updates, Billing Alerts — auquel un contact peut s’inscrire ou se désinscrire sans toucher au canal entier. Les id de sujet doivent être uniques et respecter le motif de slug ([a-z0-9][a-z0-9_-]{0,63}) ; chaque entrée comporte :
  • name (1–120 caractères) — le nom affiché sur la page.
  • description (optionnel, ≤500) — une ligne de contexte affichée près de la bascule.
  • defaultOptIn (défaut false) — comment un contact sans préférence enregistrée est traité.
  • archived (optionnel) — les sujets archivés restent dans la piste d’audit mais ne s’affichent plus sur la page.
Pièges de niveau lint : les URLs qui échouent au raffinement de schéma http(s) sont rejetées d’emblée, et les id de sujet dupliqués échouent avec « Topic ids must be unique » au lieu d’être écrasés silencieusement.

2. Émettre un lien par contact

Une fois configuré, générez un lien pour un contact à la fois avec POST /preference-center/link :
La réponse renvoie link — une URL de la forme ${DEVOTEL_WEB_URL}/preferences?token=v1…. Points à noter :
  • Le lien vise la page hébergée, pas l’endpoint JSON. Copiez-le tel quel dans vos gabarits de pied/expéditeur ; la page elle-même interroge l’endpoint de données en coulisse.
  • TTL de 30 jours. Passé ce délai, le jeton vérifie comme expiré et le contact doit demander un nouveau lien (en émettre un nouveau prend un appel API).
  • La page est agnostique du locale à l’émission. L’app web résout une redirection en préservant la requête ?token=, vous n’avez donc pas à deviner le locale du contact.

Où le placer

  • Envois marketing à corps libre : ajouté pour vous. Vous n’avez pas à placer le lien. Orbit ajoute une ligne {optOutMessage}: {link} à chaque envoi marketing à corps libre tant que votre centre de préférences est activé — sur sms et whatsapp via votre domaine court personnalisé, sur email et les autres canaux à corps libre sous forme de lien brut à jeton — et les envois gabarit sont ignorés. La même page décrit quand le pied apparaît, ce qu’écrit le clic ajouté et son lien avec la formule opérateur « Reply STOP » : voir Preference center: when Orbit appends the opt-out footer for you.
  • Envois transactionnels et gabarit : à placer vous-même. Ces envois ne portent jamais le pied ajouté, donc le lien émis ci-dessus est leur voie de désabonnement en un geste : copiez-le tel quel dans la zone de désabonnement de vos gabarits e-mail, et rédigez-le dans les copies de gabarit ou les corps transactionnels où vous en voulez un. Émettre un lien court tracké pour un emplacement est optionnel ; si l’émission de lien court échoue, le lien brut fonctionne encore — le repli est additif, jamais structurel pour la conformité.
  • Ré-opt-in piloté par la suppression. Quand un contact se réinscrit par un autre flux, vous pouvez lui remettre un lien frais pour qu’il retrouve la même page en libre-service.

3. La page publique à jeton

La page hébergée lit et écrit par deux endpoints non authentifiés protégés par le jeton signé :
  • GET /preferences/:token — renvoie le payload de la page.
  • PUT /preferences/:token — applique les mises à jour.
Les formes de jeton invalides renvoient 400 INVALID_TOKEN ; les jetons expirés ou altérés renvoient 401 TOKEN_EXPIRED avec « Please request a new link. »

Réponse GET

Le payload regroupe l’état actuel du contact et la configuration de l’organisation :
L’e-mail et le téléphone sont masqués dans la réponse publique — la page ne montre jamais l’identifiant brut avec lequel on l’appelle. consentHistory est la piste d’audit opt-in/opt-out du contact, du plus récent au plus ancien, plafonnée à 20 lignes, tirée du même registre de consentements que vos opérateurs voient dans le tableau de bord.

Corps de requête PUT

  • channelPreferences — map partielle permise (Zod partial-record) ; au moins un canal est requis.
  • frequencyPreference — optionnel, parmi all, important_only, weekly_digest, monthly_digest.
  • topicPreferences — map optionnelle { topicId: opted_in | opted_out } validée contre vos sujets configurés ; les ids inconnus sont ignorés.
  • requestDataDeletion — pose une demande d’effacement GDPR parallèlement à l’opt-out (voir section 6).
Une réponse 422 porte des problèmes par champ pour que le formulaire hébergé puisse pointer le choix invalide.

4. Comment les mises à jour circulent

Un opt-in/opt-out écrit ici n’est pas qu’un drapeau d’interface — les mêmes quatre surfaces de conformité qu’un mot-clé STOP écrit sont mises à jour :
  • Registre de consentements. Une ligne consent_records par canal (ou par sujet) est ajoutée avec source: preference_center — votre piste d’audit de charge de la preuve Art. 7 GDPR.
  • Liste de suppression. Sur tout canal désactivé, le téléphone/e-mail normalisé du contact est inséré avec le périmètre all — un blocage inter-canaux que lit chaque porte d’envoi.
  • Clôture STOP. Une clôture rapide Redis est posée à l’opt-out (et levée à un ré-opt-in complet), si bien que les lots de campagne en cours voient le changement avant que la suppression base de données, plus lente, ne se propage.
  • Journal d’audit. compliance.preference_center_updated est consigné quand vous changez la configuration, et les événements d’opt-in/out au niveau contact sont capturés dans le registre de consentements.
Ré-opt-in symétrique : un opt-in complet (tous les canaux opted_in) révoque les lignes de suppression actives du téléphone du contact et lève la clôture STOP, tandis que le registre de consentements gagne l’entrée inversée.
Sujet vs canal. Un opt-out au niveau canal gagne toujours — une bascule de sujet resserre le consentement dans les canaux que le contact accepte encore. Les ids de sujet inconnus dans un PUT sont ignorés plutôt que persistés, si bien qu’un formulaire périmé ne peut écrire de clés d’attribut arbitraires.

5. Sémantique de la bascule d’effacement GDPR

Quand showGdprDelete est activé et que le contact coche requestDataDeletion: true dans le PUT, l’API enregistre une demande d’effacement GDPR héritée — une ligne pending marquée pour votre processus d’effacement de données — parallèlement à l’opt-out. Ce marquage est voulu : la bascule d’effacement du centre de préférences marque le contact, elle ne lance pas le pipeline DSAR tracké.
La bascule d’effacement du centre de préférences n’a ni horloge SLA, ni export de données déchiffrées, ni certificat d’effacement Article 17. Pour une demande de droit à l’effacement que votre DPO peut suivre, déposez-la par l’endpoint DSAR (POST /compliance/dsar, owner/admin) — voir Data Subject Access Requests et le guide DSAR + registre des violations.

6. Le tester

Deux exemples curl prêts à coller dans un script de fumée : Enregistrer la configuration :
Attendu : 201 avec la configuration enregistrée en écho. Émettre un lien et exercer les endpoints publics :
Attendu : le GET renvoie les préférences actuelles du contact ; le PUT renvoie updated: true plus les préférences appliquées et, sur demande, une entrée gdprRequest. Échecs courants à vérifier : 400 INVALID_TOKEN (jeton malformé), 401 TOKEN_EXPIRED (TTL dépassé ou signature divergente — émettez un nouveau lien), 422 VALIDATION_ERROR (problèmes au niveau des champs dans le corps de configuration ou de mise à jour), et 404 NOT_FOUND quand le centre de préférences est désactivé ou que l’id de contact n’existe pas.