> ## 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.

# Link-Completion-Events

> Erfahren Sie, wann Ihr Nutzer ein Konto verbindet, statt dafür zu pollen.

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} />

Wenn Sie eine Verknüpfungsseite in einem Popup öffnen, kann Ihre eigene Seite mithören, was darin
passiert: Ihr Nutzer hat Reddit verbunden, er hat abgebrochen, die Verbindung ist fehlgeschlagen.
Sie erhalten ein Event pro Ergebnis, sodass Ihre UI in dem Moment aktualisiert wird, in dem es
passiert, statt nach einem Timer.

Setzen Sie [`origin`](/docs/apis/profiles/create-link-session), wenn Sie den Link erstellen, öffnen Sie
die zurückgegebene `url` in einem Popup und hören Sie zu. Mehr ist nicht nötig, und für Links, die
ohne `origin` erstellt wurden, ändert sich nichts — sie verhalten sich genau wie bisher.

<Note>
  **Sie verwenden das [eingebettete Widget](/docs/multiple-users/connect-widget)? Dann ist das bereits
  für Sie verdrahtet.** Das Skript empfängt diese Events und reicht sie mit entferntem
  `connect:`-Präfix an `connect.on("success", …)` weiter — kein `message`-Listener, keine
  Origin-Prüfung, kein `popup.closed`-Polling zu schreiben. Diese Seite ist das darunterliegende
  Wire-Protokoll und das, wogegen Sie bauen, wenn **Sie** das Fenster besitzen: Direct Mode oder
  ein Popup, das Sie selbst öffnen.
</Note>

<Note>
  Events werden nur an die exakte `origin` gesendet, die Sie auf dem Link gesetzt haben, und nur an
  das Fenster, das das Popup geöffnet hat. Prüfen Sie in Ihrem Listener trotzdem immer
  `event.origin`: Jede Seite kann eine Message an Ihr Fenster senden, und die Origin ist der
  einzige Teil einer Message, der nicht gefälscht werden kann.
</Note>

## Die Events

Jede an Ihre Seite gesendete Message ist ein Objekt der Form
`{ source: "ayrshare", version: 1, event, ... }` und trägt `network`, wann immer sich das Event auf
eines bezieht. Zwei Events tun das nicht: ein `connect:closed` von der gehosteten
Verknüpfungsseite, wo es bedeutet, dass Ihr Nutzer auf „Done“ gedrückt hat, statt dass eine
einzelne Verbindung endete, und das `connect:ready` des Widgets (siehe unten). Die Ergebnisse, die
Ihr eigener Code synthetisiert — ein blockiertes Popup oder ein von Ihrem Nutzer geschlossenes
Fenster —, kommen nicht von uns und tragen nur das, was Sie ihnen mitgeben.

<Note>
  Das [eingebettete Widget](/docs/multiple-users/connect-widget) weicht bei einem Event ab. Sein `ready`
  kündigt an, dass ein Slot bereitsteht, statt etwas über ein Netzwerk auszusagen, es trägt also
  kein `network` — während das `ready` des Popups das Netzwerk benennt, für das es geöffnet wurde.
  Wenn Sie beide Oberflächen mit einem Listener bedienen, lesen Sie `network` bei `ready` defensiv.

  Das Widget fügt außerdem einen `cancelled`-Grund hinzu, den diese Oberfläche nie sendet:
  `superseded`, wenn ein zweiter `popup()`-Aufruf einen noch laufenden Versuch ersetzt. Hier gibt
  es ein Fenster und ein Ergebnis, es gibt also nichts zu ersetzen.
</Note>

| Event               | Zusätzliche Felder                        | Gesendet, wenn                                                                                                                                                                                                                                       |
| ------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `connect:ready`     |                                           | Die Seite ist geladen und der Link wurde geprüft.                                                                                                                                                                                                    |
| `connect:started`   |                                           | Ihr Nutzer wurde zum sozialen Netzwerk geschickt.                                                                                                                                                                                                    |
| `connect:selection` | `step`                                    | Eine Auswahl oder ein Formular ist auf dem Bildschirm — Ihr Nutzer hat etwas zu tun.                                                                                                                                                                 |
| `connect:success`   | `refId`, `displayName`                    | Das Konto ist verbunden **und gespeichert**. `refId` ist das User Profile, mit dem es verbunden wurde. `displayName` ist der Kontoname und fehlt, wenn wir noch keinen haben.                                                                        |
| `connect:error`     | `message`, und `code`, wenn es einen gibt | Die Verbindung ist fehlgeschlagen. `code` entspricht der [Fehlerreferenz](/docs/errors/overview); es fehlt, wenn der Fehler keinen katalogisierten Code hat, und bei jedem Ergebnis, das Ihr eigenes Snippet synthetisiert, etwa einem blockierten Popup. |
| `connect:cancelled` | `reason`                                  | Ihr Nutzer hat abgebrochen. `reason` ist `popupClosed`, `scopesDenied` oder `userCancelled`.                                                                                                                                                         |
| `connect:closed`    |                                           | Das Popup schließt sich gleich selbst. Trägt kein `network`, wenn es von der gehosteten Verknüpfungsseite kommt, wo es bedeutet, dass Ihr Nutzer auf „Done“ gedrückt hat, statt dass eine einzelne Verbindung endete.                                |

Genau eines von `connect:success`, `connect:error` oder `connect:cancelled` kommt pro Verbindung
an. `connect:closed` gehört nicht dazu — es folgt, um Ihnen mitzuteilen, dass sich das Popup
absichtlich geschlossen hat.

`connect:success` wird erst gesendet, nachdem das Konto gespeichert wurde, sodass ein
[`GET /user`](/docs/apis/user/profile-details) direkt danach das verbundene Konto bereits anzeigt.

<Note>
  Das Popup bleibt nach `connect:error` geöffnet, damit Ihr Nutzer lesen kann, was schiefgegangen
  ist. Nach `connect:success` und `connect:cancelled` schließt es sich selbst. Hängen Sie
  `&autoClose=false` an die URL an, um es beim Debuggen in jedem Fall offen zu halten.
</Note>

## Zuhören

Zwei Dinge, die dieses Snippet tut und die leicht vergessen werden: Es prüft `event.origin`, und es
achtet auf ein Popup, das Ihr Nutzer von Hand geschlossen hat — ein geschlossenes Fenster kann
nichts mehr senden, Polling ist also der einzige Weg, es zu bemerken.

```javascript theme={"system"}
function connectAccount(url) {
  // Derive the origin from the URL you were given rather than hard-coding one:
  // if your account uses its own linking domain, the popup runs on that.
  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;
  }

  // Declared before anything can call `cleanup`: a message arriving early would
  // otherwise hit `poll` in its temporal dead zone and throw.
  let poll;

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

  const onMessage = event => {
    // Both checks, not just the origin: another tab or frame on the same origin
    // could otherwise post a message your handler would believe.
    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`, so your own handler throwing cannot leave the poll running —
      // it would later see the closed popup and report `cancelled` on top of the
      // outcome you already had. Cleanup also matters after `connect:error`,
      // where the popup stays open so your user can read it.
      try {
        handleOutcome(message);
      } finally {
        cleanup();
      }
    }
  };
  window.addEventListener("message", onMessage);

  // A hand-closed popup sends nothing, so watch for it. Wait a moment before
  // deciding: the popup closes itself right after sending, and the message can
  // still be in flight when you first see the window go.
  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);
}
```

## Fehler

`connect:error` trägt dieselben Codes wie der Rest der API — ein Code, den Sie hier sehen,
bedeutet also das, was er überall sonst bedeutet. Der eine, der spezifisch für diese Oberfläche
ist:

| Code  | Bedeutung                                                                                                                                                                                                                                |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `513` | Der Link wurde als Connect-Fenster für ein einzelnes Netzwerk geöffnet, aber nicht dafür erstellt. Nur erreichbar, wenn Sie diese URL selbst zusammenbauen — die `url`, die dieser Endpunkt zurückgibt, passt immer zum erstellten Link. |

Alles andere ist ein Fehler des sozialen Netzwerks selbst, gemeldet mit dem Code, den dieser
Fehler ohnehin hat — zum Beispiel `322` für ein Instagram-Autorisierungsproblem, was auch ein
Konto einschließt, das noch Personal statt Professional ist.

### Ein toter Link kommt anders an

Ein Link, der **abgelaufen**, **widerrufen** oder **unbekannt** ist, wird verweigert, bevor die
Seite erfahren kann, wohin Events zu senden sind — sie kann also keines senden. Ihr Nutzer sieht
den Grund und dessen Code auf dem Bildschirm, und Ihre Seite hört `connect:cancelled`, wenn er das
Fenster schließt.

Um die Fälle zu unterscheiden, pollen Sie
[Eine Link Session abrufen](/docs/apis/profiles/get-link-session): Es meldet `expired` und `revoked`
verbindlich und gibt `502` für einen Link zurück, der nicht existiert.

## Wenn Sie lieber kein Popup verwalten möchten

Zwei Optionen, und nur die zweite verzichtet auf Events.

**Lassen Sie das Widget das Fenster besitzen.** Das
[eingebettete Widget](/docs/multiple-users/connect-widget) öffnet und überwacht es für Sie und liefert
jedes Event oben an Ihre Handler. Sie erhalten weiterhin `success` in dem Moment, in dem ein Konto
gespeichert ist; Sie schreiben nur nicht die Verkabelung. Seine Frames bedeuten außerdem, dass die
meisten Netzwerke überhaupt kein Popup öffnen, bis zum Login des Netzwerks selbst.

**Pollen Sie stattdessen.** Wenn ein Popup wirklich nicht verfügbar ist — eine servergerenderte App
oder eine mobile App, die den Link im Systembrowser öffnet —, pollen Sie
[Eine Link Session abrufen](/docs/apis/profiles/get-link-session). Es meldet `completedAt` und
`completedNetworks`, sobald ein Konto gespeichert ist, also im selben Moment, in dem
`connect:success` gesendet worden wäre. Telegram schließt immer auf diesem Weg ab, da es außerhalb
des Browsers und ohne jeden Browser-Callback abgeschlossen wird.
