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

# Побудуйте власне спливаюче вікно зв'язування

> Прямий режим (Direct Mode) — підключайте по одній мережі за раз із власної кнопки, зі спливаючим вікном, яке ви відкриваєте й за яким стежите самостійно.

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={true} />

Прямий режим (Direct Mode) підключає **одну соціальну мережу за раз**, із кнопки у вашій власній
панелі керування. Ви створюєте сесію зв'язування для цієї мережі, відкриваєте повернений нею URL у
спливаючому вікні, і ваша сторінка чує, що сталося. Ваш користувач ніколи не бачить сторінку з
переліком усіх мереж і ніколи не залишає ваш застосунок довше, ніж триває власний вхід мережі.

## Яка поверхня вам потрібна

Три форми, і перші дві — це та сама інтеграція. Ця сторінка — та, яку ви будуєте самостійно.

| Поверхня | Ваш користувач бачить | White-labelling | Вибирайте, коли |
| - | - | - | - |
| **Віджет — вбудовані фрейми** ([mount](/docs/multiple-users/connect-widget#mount-a-slot)) | наші кнопки просто у вашому власному макеті; жодного спливаючого вікна до власного вікна мережі | **Найсильніший.** Ваша сторінка, ваші шрифти й кольори, і ваш користувач ніколи її не залишає | у вас є панель керування з рядком для кожної мережі, і ви хочете, щоб зв'язування відбувалося на місці. Max Pack. |
| **Віджет — ваша власна кнопка** ([popup](/docs/multiple-users/connect-widget#your-own-button)) | вашу кнопку, а потім одне спливаюче вікно для мережі | **Сильний.** Спливаюче вікно наше, але воно коротке й успадковує ваш вигляд | ви хочете власну кнопку й стилізацію та жодних фреймів у вашому макеті. Max Pack. |
| **Хостована сторінка зв'язування** ([як саме](/docs/multiple-users/api-integration-business#single-sign-on-with-jwt-authentication)) | сторінку, яку хостимо ми, з вашим логотипом, кольорами та власним CSS | **Найслабший.** Це наша сторінка, і ваш користувач залишає вашу, щоб нею скористатися | ви хочете одне посилання, яке можна роздати, або проводите онбординг електронною поштою. Нічого не потрібно будувати, Max Pack не потрібен. |

<Note>
  **Прямий режим — це спливаюче вікно третього рядка без нашого скрипта.** Якщо ваша сторінка може
  завантажити скрипт, [віджет](/docs/multiple-users/connect-widget) робить усе з цієї сторінки за вас —
  він сам відкриває спливаюче вікно, сам стежить за ним і на додачу може вбудовувати фрейми.
  Прямий режим — це те, що вам потрібно, коли ваша сторінка не може завантажити сторонній скрипт
  або коли поверхнею є нативний застосунок, а не браузер.
</Note>

<Frame caption="Ваша кнопка, ваша сторінка. Спливаюче вікно — єдине наше, що бачить ваш користувач, і лише стільки, скільки потрібно мережі.">
  <img src="https://mintcdn.com/ayrshare-docs/-2tpx3mFy9vWIObd/images/multiple-users/connect-widget-popup.webp?fit=max&auto=format&n=-2tpx3mFy9vWIObd&q=85&s=b68021d477703d97a5994ee85d299be6" alt="Клієнтська панель керування з власними кнопками Connect і спливаючим вікном Ayrshare з екраном передачі Facebook" width="2880" height="1317" data-path="images/multiple-users/connect-widget-popup.webp" />
</Frame>

## Що ви будуєте

Чотири кроки. Перший — на вашому сервері, решта — на вашій сторінці.

<Steps>
  <Step title="Створіть сесію для однієї мережі">
    З вашого бекенду викличте
    [Створення Link Session](/docs/apis/profiles/create-link-session) з `mode: "connect"`, мережею
    `network` та `origin`, на якому працює ваша сторінка.

    ```javascript Your backend theme={"system"}
    const response = await fetch("https://api.ayrshare.com/api/profiles/link-sessions", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.AYRSHARE_API_KEY}`,
        "Profile-Key": profileKey,
      },
      body: JSON.stringify({
        mode: "connect",
        network: "reddit",
        origin: "https://app.example.com",
      }),
    });

    const { url } = await response.json();
    ```

    Ви отримуєте назад `url`, що вказує на сторінку підключення однієї мережі, і жодного
    `token` — токен усередині URL. Ставтеся до всього URL як до пароля: він авторизує вашого
    користувача в його User Profile.

    <Warning>
      Створюйте сесію на своєму сервері, ніколи не в браузері. Виклик потребує вашого API Key.
    </Warning>
  </Step>

  <Step title="Відкрийте його в обробнику кліку, синхронно">
    Спливаюче вікно має бути відкрите через `window.open` **у самому обробнику кліку**. Браузер
    дозволяє спливаюче вікно, лише поки він ще опрацьовує клік вашого користувача, і цей дозвіл не
    переживає `await` — тож отримання URL спершу і його відкриття в колбеку надійно блокується
    блокувальником спливаючих вікон.

    Отримуйте URL, коли рендерите кнопку, або коли ваш користувач наводить на неї курсор. До
    моменту кліку він уже має бути у вас.

    ```javascript Your page theme={"system"}
    // `url` was fetched earlier. Nothing async between the click and window.open.
    button.addEventListener("click", () => {
      const popup = window.open(url, "ayrshare-connect", "width=600,height=800");
      if (!popup) {
        showError("Allow popups for this site to connect an account.");
        return;
      }
      listenForOutcome(popup, url);
    });
    ```
  </Step>

  <Step title="Слухайте результат">
    Оскільки ви передали `origin`, спливаюче вікно надсилає вашій сторінці подію на кожну річ, що
    в ньому відбувається: `connect:success`, `connect:error`, `connect:cancelled` і проміжні події
    прогресу. Рівно одна з цих трьох надходить на кожне підключення.

    [Події завершення зв'язування](/docs/multiple-users/link-completion-events) містять повну таблицю
    подій і готовий до копіювання слухач — `listenForOutcome` вище і є тим фрагментом. Дві його
    частини легко пропустити, і обидві спричиняють реальні баги:

    * **Перевіряйте `event.origin`** проти origin URL, який ви відкрили. Будь-яка сторінка може
      надіслати повідомлення вашому вікну, а origin — єдина частина повідомлення, яку не можна
      підробити.
    * **Опитуйте `popup.closed`**, з коротким пільговим вікном, перш ніж робити висновки.
      Спливаюче вікно, закрите вашим користувачем вручну, не надсилає взагалі нічого, і без
      пільгового вікна успішне підключення може бути повідомлене як скасоване.
  </Step>

  <Step title="Опрацюйте кожне завершення">
    | Завершення | Що воно означає | Що робити |
    | - | - | - |
    | `connect:success` | акаунт підключено **і збережено** | оновіть цей рядок. [`GET /user`](/docs/apis/user/profile-details) одразу після цього вже його показує. |
    | `connect:error` | підключення зазнало невдачі | покажіть `message`. `code` присутній, коли невдача має каталогізований код, і відсутній, коли ні. |
    | `connect:cancelled` | ваш користувач відмовився або закрив вікно | залиште рядок як був. `reason` — `popupClosed`, `scopesDenied` або `userCancelled`. |
    | нічого не надходить | посилання було прострочене, відкликане або невідоме, тож сторінка так і не дізналася, куди надсилати події | опитуйте [Отримання Link Session](/docs/apis/profiles/get-link-session), яке повідомляє ці стани авторитетно. |
  </Step>
</Steps>

<Tip>
  Додайте `&autoClose=false` до URL, поки ви розробляєте. Тоді спливаюче вікно залишається
  відкритим після кожного результату замість того, щоб закриватися самостійно, і ви можете
  прочитати, що воно каже.
</Tip>

## Нотатки для окремих мереж

Більшість мереж — це одне спливаюче вікно і нічого більше: ваш користувач натискає, авторизується
в мережі, і спливаюче вікно закривається. Ось винятки, про які варто знати перед розробкою.

<AccordionGroup>
  <Accordion title="X вимагає ваших власних API keys">
    X у прямому режимі використовує **ваші** облікові дані X Developer App, надані під час
    створення сесії як заголовки `X-Twitter-OAuth1-Api-Key` і `X-Twitter-OAuth1-Api-Secret` у
    [Створенні Link Session](/docs/apis/profiles/create-link-session).

    Сесія, створена для `twitter` або `x` **без** цих заголовків, відхиляється, коли спливаюче
    вікно відкривається: вашому користувачу кажуть, що підключення недоступне, і не показують
    жодної форми, а ваша сторінка отримує `connect:error` з `message` і **без `code`**. Це
    навмисно. Відсутні облікові дані — ваші, а не вашого користувача, і кінцевих користувачів
    ніколи не можна просити вводити ваші API keys.

    Порівняйте з Bluesky, де app password — власні облікові дані кінцевого користувача: їх сторінка
    підключення таки збирає, у формі всередині спливаючого вікна.
  </Accordion>

  <Accordion title="Facebook показує одну кнопку перед входом Meta">
    `network: "facebook"` показує одну кнопку у спливаючому вікні, і власний вхід Meta
    відкривається з цього кліку — Meta вимагає, щоб її вхід було розпочато кліком усередині
    сторінки, яка хостить її SDK. Ваш користувач клікає двічі замість одного разу; більше нічого не
    відрізняється.

    Instagram поводиться так само, коли він зв'язується **через Facebook Page** — тобто коли сесія
    несе `instagramLinkMethod: "facebook"` або коли налаштування
    [Instagram Login](/docs/multiple-users/manage-user-profiles#instagram-login) вашого акаунту вибирає
    цей потік. За прямого Instagram Login додаткової кнопки немає.
  </Accordion>

  <Accordion title="Bluesky і Telegram показують вміст сторінки, а не перенаправлення">
    Жодна з них не відправляє вашого користувача на вхід мережі. Спливаюче вікно натомість
    рендерить вміст: форму handle та app password для Bluesky і код для використання для Telegram.
    Події результату однакові в обох випадках.

    X не належить до цієї групи. З вашими ключами на сесії він завершується, ні про що не питаючи
    вашого користувача, а без них він відхиляється — див. вище.
  </Accordion>

  <Accordion title="Telegram завершується поза основним потоком">
    Telegram показує код замість перенаправлення будь-куди, і підключення завершується, коли ваш
    користувач використовує цей код — уже після зникнення спливаючого вікна. Немає браузерної
    події, на яку можна чекати, тож опитуйте
    [Отримання Link Session](/docs/apis/profiles/get-link-session) і стежте за `completedNetworks`.
  </Accordion>

  <Accordion title="Facebook Groups не можна підключити цим способом">
    Facebook Groups не є ціллю зв'язування, тож `network: "fbg"` повертає `code: 508` під час
    створення сесії.

    WhatsApp у прямому режимі **доступний**. Він відкриває Embedded Signup від Meta у спливаючому
    вікні, а події результату такі самі, як у будь-якій іншій мережі.
  </Accordion>
</AccordionGroup>

<h2 id="native-apps">
  Нативні застосунки
</h2>

Нативний застосунок відкриває той самий `url` у **системному браузері** й дізнається результат,
опитуючи [Отримання Link Session](/docs/apis/profiles/get-link-session). Задайте `origin` як вашу
власну схему (`myapp://connected`), щоб сторінка мала шлях назад у ваш застосунок; власна схема не
може отримувати події, бо немає вікна браузера, куди їх надсилати.

* **iOS** — `ASWebAuthenticationSession` або `SFSafariViewController`.
* **Android** — Chrome Custom Tabs.

<Warning>
  **Ніколи не відкривайте URL зв'язування у вбудованому webview** (`WKWebView`, `UIWebView`,
  Android `WebView`). Соціальні мережі відмовляються автентифікувати в ньому: Google відхиляє вхід
  із `disallowed_useragent`, а Meta блокує його повністю. Ваш користувач бачить власну сторінку
  помилки мережі, а не нашу, і ніщо, що ви можете змінити на своєму боці, цього не виправить.
  Наведені вище компоненти системного браузера існують саме з цієї причини й утримують користувача
  всередині вашого застосунку.
</Warning>

## Що вимагає прямий режим

<ul className="custom-bullets">
  <li>
    **[Max Pack](/docs/additional/maxpack)**. Створення сесії в режимі connect без нього повертає
    `code: 504`, хай там що ще каже запит.
  </li>

  <li>
    **`origin`** на кожній сесії. Немає allowlist і кроку реєстрації — ви надсилаєте його з кожним
    викликом. Його пропуск повертає `code: 505`; значення, яке не є origin `https`, власною схемою
    або `http://localhost`, повертає `code: 506`.
  </li>

  <li>
    **`network`**, яку ваш акаунт увімкнув. Нерозпізнана назва повертає `code: 508`; розпізнана,
    але не ввімкнена вашим акаунтом, повертає `code: 509`, що можна виправити на вашій сторінці
    [Social Networks](/docs/multiple-users/manage-user-profiles#set-social-networks-access).
  </li>

  <li>
    **Не** `allowedSocial`. Його не можна поєднувати з `network` (`code: 507`) — сесія однієї
    мережі вже сама собі allowlist.
  </li>
</ul>

Кожен із цих кодів є в довіднику
[Помилки Link Session](/docs/errors/errors-ayrshare#link-session-errors), з повідомленням, яке повертає
API.

## Наступні кроки

<Card title="Події завершення зв'язування" icon="tower-broadcast" href="/docs/multiple-users/link-completion-events" horizontal>
  Кожна подія, яку надсилає спливаюче вікно, і слухач для їх отримання.
</Card>

## Пов'язане

<Card title="Створення Link Session" icon="link" href="/docs/apis/profiles/create-link-session#connect-mode" horizontal>
  Параметри `mode`, `origin` і `network` та форми відповіді.
</Card>

<Card title="Отримання Link Session" icon="magnifying-glass" href="/docs/apis/profiles/get-link-session" horizontal>
  Опитуйте завершення, коли ви не можете використати спливаюче вікно.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.