> 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)

Cette intégration explique comment ajouter un **bouton unique « Add to Wallet »** à une boutique Salesforce Commerce Cloud. Les emplacements courants sont la **Mon compte** zone (carte de fidélité ou carte 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 maintient l’échange d’identifiants à l’abri de toute altération et évite d’exposer des secrets dans le code de la boutique.

<details>

<summary><strong>Exemples concrets</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 **active** carte-cadeau 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 id de Carte, détection de plateforme, personnalisation du QR code sur ordinateur), voir [Sur votre site web](https://github.com/TheWalletCrew/docs/tree/main/enroll/on-your-website.md).
{% endhint %}

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

Le code de la boutique Salesforce Commerce Cloud est empaqueté et déployé sous forme de **cartridges**. Une cartridge peut ajouter des contrôleurs, scripts, modèles et métadonnées de configuration, puis être intégré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 storefront (SFRA ou SiteGenesis)
* la configuration 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 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 remote include.
* **SiteGenesis**: pipelines (hérités) et modèles ISML. Le bouton est généralement ajouté sur une page de compte rendue par pipeline.

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

## Fonctionnement

Le SDK cinto de The Wallet Crew affiche le CTA approprié 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`)
* une **HMAC** signature qui prouve 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, tel que :
  * 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é d’identifiant externe convenu lors de l’onboarding (exemple : `sfcc.customerNo`).

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

Le schéma habituel est le suivant :

1. Lire l’identifiant dans le code 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 boutique afin que les surcharges soient résolues correctement.

{% hint style="info" %}
Les libellés exacts des menus de Business Manager varient selon la version de SFCC. L’essentiel 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 personnalisées du site**.

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 **préférences personnalisées au niveau du site** (et non au niveau de l’organisation).

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

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

</details>

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

{% step %}

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

Les scripts côté serveur de 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 helper exposé par la cartridge, utilisé par les contrôleurs de compte
* un pattern décorateur qui enrichit le modèle de vue avec `l’identifiant` et `identifierHmac`

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

{% step %}

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

Le SDK cinto s’appuie sur :

* un script chargeur du SDK référençant l’identifiant du tenant
* un élément conteneur marqué comme bouton « Add to Wallet »
* un `CarteType`
* 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 pour les identifiants externes (casse + échappement)

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

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

### Convention de nommage recommandée pour les clés

L’option la plus stable consiste à éviter la casse mixte dans les clés d’identifiant.

Les clés sont généralement :

* nommées avec un préfixe tel que `sfcc.`
* en minuscules
* en utilisant `_` comme séparateur si 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é en 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é en 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**, pas 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 :

* **préférences du site** pour stocker la configuration du tenant
* un **helper HMAC côté serveur**
* un **contrôleur d’inclusion distante** 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) Helper HMAC (`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 d’identifiant brute (UTF-8), encodé 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 qu’il est sûr d’inclure via une inclusion distante.

{% 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 afin d’éviter de servir l’identifiant d’un client à un autre.
    // La stratégie de cache-control diffère selon les bases SFRA, il faut donc la garder 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 CarteType = site.getCustomPreferenceValue('theWalletCrewDefaultCarteType') || '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 liés à la casse des attributs HTML.
    var externalIdentifiers = {};
    externalIdentifiers[externalKey] = { value: identifierValue, hmac: identifierHmac };

    res.render('TheWalletCrew/addToWalletButton', {
        enabled: true,
        tenantId: tenantId,
        CarteType: CarteType,
        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-CarteType="${pdict.CarteType}"
        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 conservez 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 inclusions distantes sont couramment utilisées pour éviter de polluer 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 %}

## Content Security Policy (CSP)

Certaines boutiques SFCC imposent une Content Security Policy qui bloque les scripts tiers par défaut. Si le script du SDK est bloqué, l’ajout à la liste d’autorisation de `https://sdk.neostore.cloud` pour `script-src` est requis.

Dans les projets SFRA, la CSP est souvent gérée via des middleware et des en-têtes de réponse. La modification doit suivre la stratégie CSP existante du projet (report-only ou appliquée).

## Validez le résultat

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

1. Sur iOS Safari, le CTA doit afficher **Ajouter à Apple Wallet**.
2. Sur Android Chrome, 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 que The Wallet Crew attend. Vérifiez :

* que le nom de la clé d’identifiant externe correspond à celui configuré pour SFCC (exemple : `sfcc.customerNo`)
* que la valeur de l’identifiant correspond exactement à celle signée côté serveur (sans suppression d’espaces, mise en forme ou changement de type)
* que le HMAC a été calculé avec le bon secret de tenant

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

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

* les pages spécifiques au client ne sont pas mises en cache au niveau de la page
* les inclusions distantes utilisées pour les widgets de compte ne sont pas mises en cache entre clients
* tout niveau 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 boutique 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 persisté 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 personnalisées du site 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 ressources 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 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 rendu 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 de HMAC côté serveur + rendu de modèle. 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.
