> 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/custom-connector/installation-changed-extensibility.md).

# Crochets d’installation et de désinstallation des cartes

Il est possible de créer un **connecteur personnalisé** dans **L'équipe Wallet** pour appeler une API externe chaque fois qu'une carte est **installée** ou **désinstallée** sur Apple Wallet ou Google Wallet.

Cela permet aux marques de **synchroniser l'état d'installation** avec des systèmes externes tels qu'un CRM, un outil d'analyse ou une plateforme d'automatisation marketing.

<details>

<summary>Exemples concrets</summary>

* Une marque de distribution met à jour un champ CRM comme `hasWalletPass=true` juste après l'installation. Elle cesse alors d'envoyer des rappels « ajouter au Wallet ».
* Une marque de billetterie enregistre les installations et désinstallations dans sa pile BI. Elle suit l'adoption par événement, canal et type d'appareil.
* Une marque déclenche un parcours de bienvenue après l'installation. Elle utilise `registrationSource` pour segmenter par campagne UTM.
* Une marque détecte des pics de désinstallation inhabituels après une mauvaise version. Elle effectue rapidement un retour en arrière et communique de manière proactive.

</details>

### Hooks d'exécution

La plateforme expose les hooks suivants sur le `runtime.wallet.passUpdater` point de terminaison :

* **`OnCarteInstalled`** → Déclenché lorsqu'une carte est ajoutée à Apple/Google Wallet
* **`OnCarteUninstalled`** → Déclenché lorsqu'une carte est retirée d'Apple/Google Wallet

Les deux méthodes reçoivent les mêmes paramètres :

| Paramètre               | Type                                     | Description                                                         |
| ----------------------- | ---------------------------------------- | ------------------------------------------------------------------- |
| `passId`                | `string`                                 | Identifiant unique de la carte                                      |
| `passType`              | `string`                                 | Type de carte (fidélité, carte cadeau, billet d'événement… )        |
| `identifiers`           | `Record<string, any>`                    | Identifiants clé-valeur définis sur la carte (par ex. `customerId`) |
| `device`                | `"apple"` ou `"google"`                  | plateforme Wallet                                                   |
| `additionalInformation` | `AdditionalCarteInstallationInformation` | Inclut des statistiques d'inscription                               |

### Exemple d'implémentation

Les scripts peuvent être placés dans le `server/scripts` dossier dans la configuration avancée.

```js
const API_URL = 'https://partner';
import { getSecret } from 'neo/secrets';

/** 
 * @typedef {Object} RegistrationInformation 
 * @property {number} activeRegistrationCount - Inscriptions actives. 
 * @property {number} totalRegistrationCount - Total des inscriptions. 
 **/ 

/**
 * @typedef {Object} RegistrationSource
 * @property {string[]} tags - liste des tags spécifiés par l'intégration SDK
 * @property {string} medium - support spécifié par l'intégration SDK ou utm_medium
 * @property {string} origin  - URL depuis laquelle la carte est installée - peut être remplacée par l'intégration SDK
 * @property {string} userAgent - User-Agent facultatif utilisé pour installer la carte
 */

/** 
 * @typedef {Object} AdditionalCarteInstallationInformation
 * @property {RegistrationInformation} registrationInformation - Statistiques d'inscription. 
 * @property {RegistrationSource} registrationSource - Source de l'installation lorsqu'elle est disponible 
 */

/** méthodes déclenchées lorsqu'une carte est installée 
 * @param {string} passId - identifiant unique de la carte
 * @param {string} passType - type de carte de la carte actuelle
 * @param {Record<string, any>} identifiers - paires clé-valeur des identifiants de la carte
 * @param {"apple"|"google"} device - nom de l'appareil
 * @param {AdditionalPassInstallationInformation} additionalInformation - additionalInformation liée à cette installation de carte */
 async function onPassInstalled(passId, passType, identifiers, device, additionalInformation) {
     await onPassInstallationStatusChanged(passId, passType, identifiers, device, true);
} 

/** méthodes déclenchées lorsqu'une carte est désinstallée 
 * @param {string} passId - identifiant unique de la carte 
 * @param {string} passType - type de carte de la carte actuelle
 * @param {Record<string, any>} identifiers - paires clé-valeur des identifiants de la carte
 * @param {"apple"|"google"} device - nom de l'appareil 
 * @param {AdditionalPassInstallationInformation} additionalInformation - additionalInformation liée à cette installation de carte 
 */ 
async function onPassUninstalled(passId, passType, identifiers, device, additionalInformation) { 
    await onPassInstallationStatusChanged(passId, passType, identifiers, device, false); 
} 

async function onPassInstallationStatusChanged(passId, passType, identifiers, device, isInstalled) {
  const customerId = identifiers["customerId"]; // ou tout autre identifiant externe
  const API_SECRET = await getSecret('PARTNER-API-SECRET');

  // ⚠️ Note : fetch n'est pas standard ici. Il utilise des options en PascalCase et un Body basé sur un objet.
  await fetch(API_URL + '/wallet/installation', {
    Method: "POST",
    Headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      "X-API-KEY": API_SECRET
    },
    Body: {
      customerId,
      isInstalled,
      device
    },
    ThrowOnError: false
  });
}

export default function (context) {
  context.register('runtime.wallet.passUpdater', {
    OnPassInstalled: onPassInstalled,
    OnPassUninstalled: onPassUninstalled
  });
}
```

### Exemple minimal

Pour les tests ou la journalisation uniquement :

```js
async function onPassInstalled(passId, passType, identifiers, device) {
  console.log(`Carte ${passId} installée sur ${device}`);
}

async function onPassUninstalled(passId, passType, identifiers, device) {
  console.log(`Carte ${passId} désinstallée de ${device}`);
}

export default function (context) {
  context.register('runtime.wallet.passUpdater', {
    OnPassInstalled: onPassInstalled,
    OnPassUninstalled: onPassUninstalled
  });
}
```

### Quand les événements sont-ils déclenchés ?

* **`OnCarteInstalled`** → déclenché lorsqu'un utilisateur ajoute avec succès une carte à Apple ou Google Wallet.
* **`OnCarteUninstalled`** → déclenché lorsqu'un utilisateur retire la carte de son Wallet.
* Les événements sont fiables : la plateforme garantit une livraison correcte même en cas de forte charge.

### Notes

* `fetch` est **pas le fetch standard du navigateur** — il accepte des options en PascalCase (`Method`, `Headers`, `Body`, `ThrowOnError`).
* L'authentification est flexible : vous pouvez utiliser des clés API (via `getSecret`) ou OAuth avec le custom `fetch`.
* Il n'existe aucune restriction de plateforme : l'exécution est sûre et entièrement gérée.

### FAQ

<details>

<summary>Ces événements sont-ils en temps réel ?</summary>

Ils se déclenchent lorsque la carte est ajoutée ou retirée du Wallet. En pratique, vous devriez les considérer comme quasi temps réel. Concevez toujours votre API pour qu'elle soit idempotente, afin que les nouvelles tentatives ne créent pas de doublons.

</details>

<details>

<summary>Que se passe-t-il si mon API est indisponible ?</summary>

Le code de votre connecteur contrôle l'appel. Vous devez gérer les délais d'attente et les erreurs de manière élégante. Si le système externe est critique, mettez en place des tentatives de réessai et une stratégie de dead-letter de votre côté.

</details>

<details>

<summary>Puis-je utiliser cela pour déclencher des e-mails ou des campagnes push ?</summary>

Oui. Le schéma le plus courant consiste à appeler votre plateforme d'automatisation marketing (directement ou via votre backend) et à déclencher un parcours lors de l'installation. Utilisez les événements de désinstallation pour arrêter ou adapter les communications.

</details>

<details>

<summary>Qu'est-ce qui est inclus dans <code>additionalInformation</code>?</summary>

Il peut inclure des statistiques d'inscription et, lorsqu'elle est disponible, la source d'installation. Utilisez-le pour mesurer l'adoption et attribuer les installations à une campagne ou à une intégration SDK.

</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/custom-connector/installation-changed-extensibility.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.
