> For the complete documentation index, see [llms.txt](https://docs.thewalletcrew.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.thewalletcrew.io/connectors/fr/e-commerce/salesforce-commerce-cloud.md).

# Salesforce Commerce Cloud (SFCC)

Ajoutez des boutons « Add to Wallet » Apple Wallet et Google Wallet à une boutique Salesforce Commerce Cloud à l’aide d’un cartridge, d’une signature HMAC côté serveur et du SDK cinto de The Wallet Crew.

Cette intégration explique comment ajouter un **bouton unique « Add to Wallet »** à une vitrine Salesforce Commerce Cloud. Les emplacements courants sont le **Mon compte** espace (carte de fidélité ou d’adhésion) et les pages authentifiées où un identifiant stable est disponible (par exemple une liste de cartes-cadeaux). Les pages Pick & collect peuvent également convenir lorsqu’une carte de retrait est utilisée comme jeton de scan en magasin.

Un identifiant stable disponible dans la session client est signé côté serveur, puis transmis au SDK cinto de The Wallet Crew comme identifiant externe. Cela rend l’échange d’identifiant à l’abri des altérations et évite d’exposer des secrets dans le code de la vitrine.

<details>

<summary><strong>Exemples réels</strong></summary>

* Un programme de fidélité affiche « Add to Wallet » dans **Mon compte** pour les clients connectés.
* Un programme de cartes-cadeaux affiche un bouton par **carte-cadeau** active dans le Wallet du compte.
* Un flux pick & collect affiche un CTA de carte de retrait sur une page de retrait dédiée, en utilisant une référence de retrait comme identifiant.

</details>

{% hint style="info" %}
Pour l’utilisation générique du SDK cinto (mode identifiant de carte, détection de plateforme, personnalisation du QR sur ordinateur), voir [Sur votre site web](/guides-enrolment/fr/inscription/on-your-website.md).
{% endhint %}

## Concepts SFCC utilisés dans cette intégration

Le code de la vitrine Salesforce Commerce Cloud est empaqueté et déployé sous forme de **cartridges**. Une cartridge peut ajouter des contrôleurs, des scripts, des modèles et des métadonnées de configuration, puis être branchée à un site en l’ajoutant au **chemin des cartridges**.

Ce guide suppose qu’une cartridge dédiée est créée pour l’intégration The Wallet Crew, généralement nommée comme `int_TheWalletCrew`. La cartridge est ensuite référencée par :

* l’application de vitrine (SFRA ou SiteGenesis)
* la configuration de Business Manager (préférences du site et, éventuellement, objets personnalisés)

### Cartridge

Une **cartridge** est l’unité de déploiement dans SFCC. L’ordre des cartridges compte car SFCC résout les modèles et les scripts en parcourant le chemin des cartridges de gauche à droite.

### SFRA vs SiteGenesis

Les deux architectures peuvent prendre en charge l’intégration :

* **SFRA**: contrôleurs et modèles ISML. Le bouton est généralement ajouté dans un modèle de compte ou un include distant.
* **SiteGenesis**: pipelines (hérités) et modèles ISML. Le bouton est généralement ajouté dans une page de compte rendue par un pipeline.

Le modèle de sécurité reste identique. Le HMAC est calculé côté serveur et jamais en JavaScript côté navigateur.

## Comment ça marche

Le SDK cinto de The Wallet Crew affiche le bon CTA selon l’appareil.

Sur iOS, le bouton télécharge une Carte Apple Wallet. Sur Android, il ouvre Google Wallet. Sur ordinateur, le SDK redirige vers une page de Carte hébergée qui peut être scannée ou ouverte sur mobile.

Dans cette configuration SFCC, la Carte est récupérée à l’aide de :

* un **type de Carte** (exemple : `utilisateur`)
* un identifiant SFCC stable envoyé comme **identifiant externe** (exemple : `sfcc.customerNo`)
* un **HMAC** signature prouvant que l’identifiant a été émis par le backend de la marque

{% hint style="warning" %}
Le HMAC doit être calculé côté serveur. Il ne doit pas être généré dans le navigateur.
{% endhint %}

## Prérequis

* Un modèle de Carte et une émission de Carte déjà configurés dans The Wallet Crew.
* L’identifiant du tenant The Wallet Crew disponible (utilisé par l’URL du script du SDK).
* Un identifiant stable disponible sur les pages authentifiées, par exemple :
  * SFCC `CustomerNo` (typique pour les cartes de fidélité)
  * référence de retrait (typique pour les cartes de retrait pick & collect)
  * identifiant de carte-cadeau (lorsque les cartes-cadeaux sont stockées dans SFCC ou dans un système connecté)
* Le nom de clé de l’identifiant externe convenu lors de l’onboarding (exemple : `sfcc.customerNo`).

## Implémentez l’intégration sous forme de cartridge

Le schéma typique est :

1. Lire l’identifiant dans le code côté serveur SFCC.
2. Calculer un HMAC avec le secret du tenant.
3. Rendre un conteneur cinto dans le modèle ISML avec identifiant + HMAC.
4. Charger le SDK cinto depuis `sdk.neostore.cloud`.

{% stepper %}
{% step %}

#### Ajouter la cartridge au chemin des cartridges

Après avoir déployé la cartridge d’intégration sur l’instance, ajoutez-la au chemin des cartridges du site dans Business Manager. La cartridge doit être placée **avant** la cartridge de base de la vitrine afin que les surcharges se résolvent correctement.

{% hint style="info" %}
Les libellés exacts des menus Business Manager varient selon la version de SFCC. L’important est le **chemin des cartridges au niveau du site** (et non le chemin global).
{% endhint %}
{% endstep %}

{% step %}

#### Stocker la configuration du tenant comme préférences du site

Les valeurs et secrets du tenant doivent rester côté serveur. Dans SFCC, cela se fait généralement avec **des préférences de site personnalisées**.

Au minimum, ces valeurs sont généralement requises.

<details>

<summary><strong>Préférences recommandées (ID, types, exemples)</strong></summary>

Ces valeurs sont généralement créées comme **des préférences personnalisées au niveau du site** (et non au niveau de l’organisation).

* `theWalletCrewTenantId` (Chaîne)\
  Exemple : `molia`
* `theWalletCrewHmacSecret` (Mot de passe)\
  Exemple : `I1M8emrrJSns4Hnuibbm45eWfLQMosPGKSp1JzKsCrXeWmhjE8lZhxC2tfSRX5IJ`
* `theWalletCrewDefaultPassType` (Chaîne)\
  Exemple : `utilisateur`
* `theWalletCrewExternalIdentifierKey` (Chaîne)\
  Exemple : `sfcc.customerNo`
* `theWalletCrewLanguage` (Chaîne, facultatif)\
  Exemple : `fr`\
  Lorsqu’il est omis, cinto utilise la détection de la langue du navigateur.

{% hint style="info" %}
Conserver le secret sous forme de **Mot de passe** préférence aide à éviter toute divulgation accidentelle dans les exports de l’interface et les captures d’écran.
{% endhint %}

</details>

{% hint style="warning" %}
Le secret HMAC ne doit pas être stocké dans les modèles, les actifs de contenu ou toute configuration côté client.
{% endhint %}
{% endstep %}

{% step %}

#### Calculer le HMAC côté serveur

Les scripts côté serveur SFCC peuvent calculer un HMAC SHA-256 à l’aide du secret du tenant et de la valeur exacte de l’identifiant.

Choix d’implémentation courants :

* un script utilitaire exposé par la cartridge, utilisé par les contrôleurs du compte
* un pattern décorateur qui enrichit le modèle de vue avec `identifiant` et `identifierHmac`

La mise en cache doit être gérée avec soin. Les pages spécifiques à un client ne doivent pas partager du HTML mis en cache entre clients lorsque l’identifiant est intégré au balisage.
{% endstep %}

{% step %}

#### Afficher le bouton « Add to Wallet » dans ISML

Le SDK cinto s’appuie sur :

* un script chargeur du SDK faisant référence à l’identifiant du tenant
* un élément conteneur marqué comme bouton « Add to Wallet »
* un `passType`
* une paire clé/valeur d’identifiant externe plus le HMAC côté serveur

La cartridge d’intégration fournit généralement un fragment ISML pouvant être inclus là où c’est nécessaire (tableau de bord du compte, liste de cartes-cadeaux, page pick & collect).
{% endstep %}
{% endstepper %}

## Conventions d’identifiant externe (casse + échappement)

Le SDK cinto peut récupérer une Carte à partir d’un identifiant externe :

* `passType` (exemple : `utilisateur`)
* `externalIdentifier.key` (exemple : `sfcc.customerNo`)
* `externalIdentifier.value` (exemple : `00012345`)
* `externalIdentifier.hmac` (HMAC-SHA256 de la valeur)

### Convention recommandée pour le nom des clés

L’option la plus stable consiste à éviter le mélange de majuscules et minuscules dans les clés d’identifiant.

Les clés sont généralement :

* avec un préfixe d’espace de noms comme `sfcc.`
* en minuscules
* en utilisant `_` comme séparateur lorsque nécessaire

Exemples :

* `sfcc.customer_no`
* `sfcc.pickup_ref`
* `sfcc.gift_card_id`

{% hint style="info" %}
Si le tenant The Wallet Crew est déjà configuré avec une clé à casse mixte, la modifier peut avoir un impact sur les installations existantes. Un changement de nom de clé doit être traité comme un sujet de migration.
{% endhint %}

### Si une clé à casse mixte doit être utilisée dans les attributs HTML

Les navigateurs traitent les noms d’attributs HTML en minuscules. cinto prend en charge une règle d’échappement pour les caractères majuscules dans `data-neostore-externalIdentifiers-...` attributs :

* Préfixez un caractère majuscule avec `_` dans le nom de l’attribut.
* `y2.customer_Id` est interprété comme `y2.customerId`.

Appliqué aux exemples SFCC :

* Clé d’identifiant dans The Wallet Crew : `sfcc.customerNo`
* Clé d’identifiant dans les attributs HTML : `sfcc.customer_No`

Cela n’affecte que le **nom de l’attribut**, et non la valeur signée.

## Implémentation de référence SFRA à copier/coller (contrôleur + fragment ISML)

Cette implémentation de référence utilise :

* **les préférences du site** pour stocker la configuration du tenant
* un **un utilitaire HMAC côté serveur**
* un **un contrôleur d’include distant** qui rend un fragment ISML

Elle est conçue pour être collée dans une cartridge dédiée (exemple : `int_TheWalletCrew`) et appelée depuis une page de compte.

### Structure des fichiers de la cartridge

* `cartridge/scripts/TheWalletCrew/hmac.js`
* `cartridge/controllers/TheWalletCrew.js`
* `cartridge/templates/default/TheWalletCrew/addToWalletButton.isml`

### 1) HMAC helper (`cartridge/scripts/TheWalletCrew/hmac.js`)

{% code title="cartridge/scripts/TheWalletCrew/hmac.js" %}

```javascript
'use strict';

var Mac = require('dw/crypto/Mac');
var Encoding = require('dw/crypto/Encoding');

/**
 * HMAC-SHA256 sur la chaîne brute de l’identifiant (UTF-8), encodée en hexadécimal.
 * La sortie est mise en minuscules pour correspondre aux exemples cinto.
 */
function hmacSha256Hex(secret, identifierValue) {
    var mac = new Mac(Mac.HMAC_SHA_256);
    var bytes = mac.digest(identifierValue, secret);
    return Encoding.toHex(bytes).toLowerCase();
}

module.exports = {
    hmacSha256Hex: hmacSha256Hex
};
```

{% endcode %}

### 2) Contrôleur (`cartridge/controllers/TheWalletCrew.js`)

Ce contrôleur rend un widget qui peut être inclus sans risque en tant qu’include distant.

{% code title="cartridge/controllers/TheWalletCrew\.js" %}

```javascript
'use strict';

var server = require('server');
var Site = require('dw/system/Site');

var theWalletCrewHmac = require('*/cartridge/scripts/TheWalletCrew/hmac');

server.get('Button', function (req, res, next) {
    // Désactiver la mise en cache pour éviter de servir l’identifiant d’un client à un autre.
    // La stratégie de cache-control diffère selon les bases SFRA, donc gardons-la explicite.
    res.setHttpHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
    res.setHttpHeader('Pragma', 'no-cache');

    var site = Site.getCurrent();
    var tenantId = site.getCustomPreferenceValue('theWalletCrewTenantId');
    var secret = site.getCustomPreferenceValue('theWalletCrewHmacSecret');
    var passType = site.getCustomPreferenceValue('theWalletCrewDefaultPassType') || 'user';
    var externalKey = site.getCustomPreferenceValue('theWalletCrewExternalIdentifierKey') || 'sfcc.customerNo';
    var language = site.getCustomPreferenceValue('theWalletCrewLanguage');

    // Exemple d’identifiant : numéro client connecté.
    var identifierValue = (customer && customer.profile) ? customer.profile.customerNo : null;

    if (!tenantId || !secret || !identifierValue) {
        res.render('TheWalletCrew/addToWalletButton', { enabled: false });
        return next();
    }

    var identifierHmac = theWalletCrewHmac.hmacSha256Hex(secret, identifierValue);

    // Recommandé dans les modèles côté serveur : utilisez la forme d’attribut JSON.
    // Cela évite les pièges de casse des attributs HTML.
    var externalIdentifiers = {};
    externalIdentifiers[externalKey] = { value: identifierValue, hmac: identifierHmac };

    res.render('TheWalletCrew/addToWalletButton', {
        enabled: true,
        tenantId: tenantId,
        passType: passType,
        language: language,
        externalIdentifiersJson: JSON.stringify(externalIdentifiers)
    });

    return next();
});

module.exports = server.exports();
```

{% endcode %}

### 3) Fragment ISML (`cartridge/templates/default/TheWalletCrew/addToWalletButton.isml`)

{% code title="cartridge/templates/default/TheWalletCrew/addToWalletButton.isml" %}

```html
<isif condition="${pdict.enabled}">
    <script type="text/javascript">
    (function (n, e, o) {
        var s=n.createElement("script");
        s.src="https://sdk.neostore.cloud/scripts/"+e+"/cinto@1";
        s.async=1;
        s.onload=function(){neostore.cinto.initialize(e,o);};
        n.body.appendChild(s);
    })(document, "${pdict.tenantId}", <isprint value="${pdict.language ? ('{ \"language\": \"' + pdict.language + '\" }') : '{ }'}" encoding="off" />);
    </script>

    <div
        data-neostore-addToWalletButton
        data-neostore-passType="${pdict.passType}"
        data-neostore-externalIdentifiers="<isprint value="${pdict.externalIdentifiersJson}" encoding="off" />">
    </div>
</isif>
```

{% endcode %}

{% hint style="warning" %}
Le chargeur de script doit être inclus **une seule fois par page**. Lorsque plusieurs boutons sont rendus sur la même page, déplacez le chargeur dans un fragment de pied de page partagé et ne gardez que le `<div data-neostore-addToWalletButton ...>` balisage dans le modèle du widget.
{% endhint %}

### 4) Inclure le widget dans un modèle de compte

Dans SFRA, les includes distants sont couramment utilisés pour éviter de surcharger le contrôleur principal et pour garder la mise en cache explicite.

{% code title="Exemple d’inclusion (ISML)" %}

```html
<isinclude url="${URLUtils.url('TheWalletCrew-Button')}" />
```

{% endcode %}

## Politique de sécurité du contenu (CSP)

Certaines vitrines SFCC appliquent une politique de sécurité du contenu qui bloque les scripts tiers par défaut. Si le script du SDK est bloqué, la mise en liste blanche de `https://sdk.neostore.cloud` pour `script-src` est requise.

Dans les projets SFRA, la CSP est souvent gérée via des intergiciels et des en-têtes de réponse. Le changement doit suivre la stratégie CSP existante du projet (mode rapport uniquement vs appliqué).

## Valider le résultat

La validation couvre généralement le rendu de la plateforme et l’installation de la Carte.

1. Dans Safari sur iOS, le CTA doit afficher **Ajouter à Apple Wallet**.
2. Dans Chrome sur Android, le CTA doit afficher **Ajouter à Google Wallet**.
3. Sur ordinateur, le CTA doit rediriger vers une page de Carte hébergée.
4. Après installation, la Carte doit être visible dans Apple Wallet ou Google Wallet.

## Dépannage

### Le bouton ne s’affiche pas

Les causes courantes sont un script SDK bloqué (CSP) ou un balisage manquant. La page rendue doit contenir le chargeur du SDK et l’élément conteneur cinto.

### Cliquer sur le bouton provoque une erreur

Cela signifie généralement que l’identifiant externe ou le HMAC ne correspond pas à ce qu’attend The Wallet Crew. Vérifiez :

* le nom de clé de l’identifiant externe correspond à celui configuré pour SFCC (exemple : `sfcc.customerNo`)
* la valeur de l’identifiant correspond exactement à ce qui est signé côté serveur (aucun troncage, formatage ou changement de type)
* le HMAC a été calculé avec le bon secret du tenant

### Le bouton s’affiche pour le mauvais client

Cela indique généralement une mise en cache HTML entre sessions. Assurez-vous que :

* les pages spécifiques à un client ne sont pas mises en cache au niveau de la page
* les includes distants utilisés pour les widgets de compte ne sont pas mis en cache entre clients
* toute couche CDN respecte les cookies de session pour les pages authentifiées

## FAQ

<details>

<summary><strong>Qu’est-ce qu’une cartridge dans SFCC ?</strong></summary>

Une cartridge est l’unité déployable qui contient le code de la vitrine et les métadonnées. Le chemin des cartridges du site définit quelles cartridges sont actives et dans quel ordre elles sont résolues.

</details>

<details>

<summary><strong>Quel identifiant fonctionne le mieux pour les cartes de fidélité ?</strong></summary>

Le numéro client SFCC (`CustomerNo`) est couramment utilisé car il est stable et disponible sur les pages authentifiées. Un identifiant CRM peut également être utilisé s’il est conservé sur le profil et reste stable dans le temps.

</details>

<details>

<summary><strong>Où le secret du tenant doit-il être stocké dans SFCC ?</strong></summary>

Les préférences de site personnalisées sont généralement utilisées car elles restent côté serveur et peuvent être gérées par site. Le secret ne doit jamais être exposé dans les modèles, les actifs de contenu ou le JavaScript du navigateur.

</details>

<details>

<summary><strong>La même approche peut-elle être utilisée pour les cartes-cadeaux et le pick &#x26; collect ?</strong></summary>

Oui. Le même schéma fonctionne tant qu’un identifiant stable existe pour l’objet et que le bouton peut être affiché sur une page qui a accès à cet identifiant côté serveur.

</details>

<details>

<summary><strong>L’intégration nécessite-t-elle SFRA ?</strong></summary>

Non. SFRA et SiteGenesis peuvent tous deux prendre en charge le même schéma HMAC côté serveur + rendu de modèles. Seuls les points d’entrée d’implémentation diffèrent (contrôleurs vs pipelines).

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.thewalletcrew.io/connectors/fr/e-commerce/salesforce-commerce-cloud.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
