> ## Documentation Index
> Fetch the complete documentation index at: https://www.ayrshare.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Événements de fin de liaison

> Soyez informé lorsque votre utilisateur connecte un compte, au lieu de le poller.

export const PlansAvailable = ({plans = [], maxPackRequired}) => {
  let displayPlans = plans;
  if (plans && plans.length === 1) {
    const lowerCasePlan = plans[0].toLowerCase();
    if (lowerCasePlan === "business") {
      displayPlans = ["Launch", "Business", "Enterprise"];
    } else if (lowerCasePlan === "premium") {
      displayPlans = ["Premium", "Launch", "Business", "Enterprise"];
    }
  }
  return <Note>
Available on {displayPlans.length === 1 ? "the " : ""}
{displayPlans.join(", ").replace(/\b\w/g, l => l.toUpperCase())}{" "}
{displayPlans.length > 1 ? "plans" : "plan"}.

{maxPackRequired && <span onClick={() => window.open('https://www.ayrshare.com/docs/additional/maxpack', '_self')} className="flex items-center mt-2 cursor-pointer">
 <span className="px-1.5 py-0.5 rounded text-sm" style={{
    backgroundColor: '#C264B6',
    color: 'white',
    fontSize: '12px'
  }}>
   Max Pack required
 </span>
</span>}
</Note>;
};

<PlansAvailable plans={["business"]} maxPackRequired={false} />

Lorsque vous ouvrez une page de liaison dans une popup, votre propre page peut écouter ce qui s'y
passe : votre utilisateur a connecté Reddit, il a renoncé, la connexion a échoué. Vous recevez un
événement par résultat, donc votre UI se met à jour au moment où cela se produit plutôt que sur un
timer.

Définissez [`origin`](/docs/apis/profiles/create-link-session) lorsque vous créez le lien, ouvrez l'`url`
retournée dans une popup, et écoutez. Rien d'autre n'est requis, et rien ne change pour les liens
créés sans `origin` — ils se comportent exactement comme ils l'ont toujours fait.

<Note>
  **Vous utilisez le [widget intégré](/docs/multiple-users/connect-widget) ? Tout cela est déjà câblé
  pour vous.** Le script reçoit ces événements et les transmet à `connect.on("success", …)` avec le
  préfixe `connect:` retiré — pas de listener `message`, pas de vérification d'origine, pas de
  polling de `popup.closed` à écrire. Cette page est le protocole de câblage sous-jacent, et ce sur
  quoi vous construisez lorsque c'est **vous** qui possédez la fenêtre : le mode direct, ou une
  popup que vous ouvrez vous-même.
</Note>

<Note>
  Les événements ne sont envoyés qu'à l'`origin` exacte que vous avez définie sur le lien, et
  seulement à la fenêtre qui a ouvert la popup. Vérifiez quand même toujours `event.origin` dans
  votre listener : n'importe quelle page peut poster un message à votre fenêtre, et l'origine est
  la seule partie d'un message qui ne peut pas être falsifiée.
</Note>

## Les événements

Chaque message posté à votre page est un objet de la forme
`{ source: "ayrshare", version: 1, event, ... }`, et porte `network` chaque fois que l'événement
concerne un réseau. Deux événements n'en portent pas : un `connect:closed` provenant de la page de
liaison hébergée, où il signifie que votre utilisateur a appuyé sur Done plutôt que la fin d'une
connexion, et le `connect:ready` du widget (voir ci-dessous). Les résultats que votre propre code
synthétise — une popup bloquée, ou une fenêtre que votre utilisateur a fermée — ne viennent pas de
nous et ne portent que ce que vous leur donnez.

<Note>
  Le [widget intégré](/docs/multiple-users/connect-widget) diffère sur un événement. Son `ready` annonce
  qu'un emplacement est actif plutôt que quoi que ce soit à propos d'un réseau, donc il ne porte
  pas de `network` — tandis que le `ready` de la popup nomme le réseau pour lequel elle a été
  ouverte. Si vous gérez les deux surfaces depuis un seul listener, lisez `network` de manière
  défensive sur `ready`.

  Le widget ajoute aussi une raison de `cancelled` que cette surface n'envoie jamais :
  `superseded`, lorsqu'un second appel à `popup()` remplace une tentative encore en cours. Ici, il
  y a une fenêtre et un résultat, donc il n'y a rien à remplacer.
</Note>

| Événement           | Champs supplémentaires                  | Envoyé quand                                                                                                                                                                                                                          |
| ------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `connect:ready`     |                                         | La page s'est chargée et le lien a été vérifié.                                                                                                                                                                                       |
| `connect:started`   |                                         | Votre utilisateur a été envoyé vers le réseau social.                                                                                                                                                                                 |
| `connect:selection` | `step`                                  | Un sélecteur ou un formulaire est à l'écran — votre utilisateur a quelque chose à faire.                                                                                                                                              |
| `connect:success`   | `refId`, `displayName`                  | Le compte est connecté **et enregistré**. `refId` est le User Profile auquel il a été connecté. `displayName` est le nom du compte, et est omis lorsque nous ne l'avons pas encore.                                                   |
| `connect:error`     | `message`, et `code` quand il y en a un | La connexion a échoué. `code` correspond à la [référence des erreurs](/docs/errors/overview) ; il est absent lorsque l'échec n'a pas de code catalogué, et sur tout résultat que votre propre snippet synthétise, comme une popup bloquée. |
| `connect:cancelled` | `reason`                                | Votre utilisateur a renoncé. `reason` est `popupClosed`, `scopesDenied` ou `userCancelled`.                                                                                                                                           |
| `connect:closed`    |                                         | La popup est sur le point de se fermer d'elle-même. Ne porte pas de `network` lorsqu'il provient de la page de liaison hébergée, où il signifie que votre utilisateur a appuyé sur Done plutôt que la fin d'une connexion.            |

Exactement l'un de `connect:success`, `connect:error` ou `connect:cancelled` arrive par connexion.
`connect:closed` n'en fait pas partie — il suit, pour vous dire que la popup s'est fermée
volontairement.

`connect:success` n'est envoyé qu'une fois le compte enregistré, donc un
[`GET /user`](/docs/apis/user/profile-details) immédiatement après affiche déjà le compte connecté.

<Note>
  La popup reste ouverte après `connect:error` pour que votre utilisateur puisse lire ce qui s'est
  mal passé. Elle se ferme d'elle-même après `connect:success` et `connect:cancelled`. Ajoutez
  `&autoClose=false` à l'URL pour la garder ouverte dans tous les cas pendant le débogage.
</Note>

## Écouter

Deux choses que fait ce snippet et qui sont faciles à omettre. Il vérifie `event.origin`, et il
surveille une popup que votre utilisateur a fermée à la main — une fenêtre fermée ne peut rien
envoyer, donc le polling est le seul moyen de s'en apercevoir.

```javascript theme={"system"}
function connectAccount(url) {
  // Dérivez l'origine de l'URL qu'on vous a donnée plutôt que d'en coder une en dur :
  // si votre compte utilise son propre domaine de liaison, la popup s'exécute dessus.
  const popupOrigin = new URL(url).origin;

  const popup = window.open(url, "ayrshare-connect", "width=600,height=800");
  if (!popup) {
    handleOutcome({ event: "connect:error", message: "The popup was blocked." });
    return;
  }

  // Déclaré avant que quoi que ce soit ne puisse appeler `cleanup` : un message arrivant tôt
  // atteindrait sinon `poll` dans sa zone morte temporelle et lèverait une exception.
  let poll;

  const cleanup = () => {
    clearInterval(poll);
    window.removeEventListener("message", onMessage);
  };

  const onMessage = event => {
    // Les deux vérifications, pas seulement l'origine : un autre onglet ou une autre frame sur la
    // même origine pourrait sinon poster un message que votre handler croirait.
    if (event.origin !== popupOrigin || event.source !== popup) return;
    const message = event.data;
    if (!message || message.source !== "ayrshare") return;

    if (["connect:success", "connect:error", "connect:cancelled"].includes(message.event)) {
      // `finally`, pour qu'une exception dans votre propre handler ne puisse pas laisser le poll
      // tourner — il verrait plus tard la popup fermée et rapporterait `cancelled` par-dessus le
      // résultat que vous aviez déjà. Le nettoyage compte aussi après `connect:error`,
      // où la popup reste ouverte pour que votre utilisateur puisse la lire.
      try {
        handleOutcome(message);
      } finally {
        cleanup();
      }
    }
  };
  window.addEventListener("message", onMessage);

  // Une popup fermée à la main n'envoie rien, alors surveillez-la. Attendez un instant avant de
  // décider : la popup se ferme d'elle-même juste après l'envoi, et le message peut
  // encore être en transit lorsque vous voyez la fenêtre disparaître.
  let closedAt = null;
  poll = setInterval(() => {
    if (!popup.closed) return;
    if (closedAt === null) {
      closedAt = Date.now();
      return;
    }
    if (Date.now() - closedAt < 750) return;

    cleanup();
    handleOutcome({ event: "connect:cancelled", reason: "popupClosed" });
  }, 500);
}
```

## Erreurs

`connect:error` porte les mêmes codes que le reste de l'API, donc un code que vous voyez ici
signifie ce qu'il signifie partout ailleurs. Le seul spécifique à cette surface :

| Code  | Signification                                                                                                                                                                                                                                 |
| ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `513` | Le lien a été ouvert comme une fenêtre de connexion mono-réseau, mais n'a pas été créé pour cela. Seulement atteignable si vous construisez cette URL vous-même — l'`url` que cet endpoint retourne correspond toujours au lien qu'il a créé. |

Tout le reste est l'échec propre au réseau social, rapporté avec le code que cet échec possède déjà
— par exemple `322` pour un problème d'autorisation Instagram, ce qui inclut un compte encore
Personnel plutôt que Professionnel.

### Un lien mort arrive différemment

Un lien **expiré**, **révoqué** ou **inconnu** est refusé avant que la page ne puisse apprendre où
envoyer les événements, donc il ne peut pas en envoyer. Votre utilisateur voit la raison et son
code à l'écran, et votre page entend `connect:cancelled` lorsqu'il ferme la fenêtre.

Pour les distinguer, pollez [Obtenir une session de liaison](/docs/apis/profiles/get-link-session) : il
rapporte `expired` et `revoked` de manière fiable, et retourne `502` pour un lien qui n'existe pas.

## Si vous préférez ne pas gérer de popup

Deux options, et seule la seconde renonce aux événements.

**Laissez le widget posséder la fenêtre.** Le [widget intégré](/docs/multiple-users/connect-widget)
l'ouvre et la surveille pour vous et délivre chaque événement ci-dessus à vos handlers. Vous
recevez toujours `success` au moment où un compte est enregistré ; vous n'écrivez simplement pas la
plomberie. Ses frames font aussi que la plupart des réseaux n'ouvrent jamais de popup du tout avant
la connexion propre du réseau.

**Pollez à la place.** Si une popup n'est réellement pas disponible — une application rendue côté
serveur, ou une application mobile ouvrant le lien dans le navigateur système — pollez
[Obtenir une session de liaison](/docs/apis/profiles/get-link-session). Il rapporte `completedAt` et
`completedNetworks` dès qu'un compte est enregistré, ce qui est le même moment où
`connect:success` aurait été envoyé. Telegram se termine toujours de cette manière, puisqu'il se
conclut hors bande sans aucun callback navigateur.
