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

# Огляд соціального зв'язування

> Як ваші користувачі підключають свої соціальні акаунти — три поверхні, сесія зв'язування в основі всіх них і спільні для них параметри.

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

Ваші користувачі підключають свої соціальні акаунти самостійно — вони автентифікуються
безпосередньо в кожній мережі, і ви ніколи не бачите й не зберігаєте їхні облікові дані. Усе на
цій сторінці — про те, як довести їх до цього моменту й дізнатися, чим він закінчився.

Одна річ спільна для кожного маршруту: **сесія зв'язування**, створена за допомогою
[Створення Link Session](/docs/apis/profiles/create-link-session) з вашим API Key і `Profile-Key`.
Нічого не підписується на вашому боці, і в процесі немає приватного ключа.

## Три способи підключення

Три форми, і перші дві — це та сама інтеграція. Вибирайте для кожного потоку окремо — вони не
виключають одна одну, і чимало інтеграцій використовують хостовану сторінку для онбордингу, а
віджет — усередині застосунку згодом.

| Поверхня | Ваш користувач бачить | 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>
  Два рядки з віджетом — це **одна інтеграція**, а не дві. Один `init` дає обидва варіанти:
  монтуйте фрейми там, де мають бути наші кнопки, і викликайте `popup()` з власної кнопки всюди
  інде. Вони ділять одну сесію і звітують через ті самі обробники.

  [Прямий режим](/docs/multiple-users/connect-direct-mode) (Direct Mode) — це те саме спливаюче вікно,
  але **без** нашого скрипта — для сторінки із суворою Content-Security-Policy, сторінки з
  серверним рендерингом або нативного застосунку. Там ви відкриваєте спливаюче вікно й стежите за
  ним самостійно.

  **Не впевнені?** Почніть із хостованої сторінки зв'язування. Їй не потрібні Max Pack і додаткові
  параметри, і це найшвидший шлях до чогось працюючого — перехід на віджет пізніше не змінює
  спосіб створення сесій.
</Note>

## Створення посилання

Викличте [Створення Link Session](/docs/apis/profiles/create-link-session), передавши `Profile-Key`
користувача в заголовку. Для хостованої сторінки це весь запит:

```bash cURL theme={"system"}
curl -X POST https://api.ayrshare.com/api/profiles/link-sessions \
  -H "Authorization: Bearer $AYRSHARE_API_KEY" \
  -H "Profile-Key: $PROFILE_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

Ви отримуєте назад `url` із короткочасним непрозорим токеном:

```javascript Linking URL theme={"system"}
https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=YOUR_DOMAIN
```

Ви також можете [перевірити, чи посилання відкривали](/docs/apis/profiles/get-link-session), і
[відкликати його](/docs/apis/profiles/revoke-link-session) до завершення строку дії.

<Note>
  Це однохвилинне відео показує створення посилання. Його записали до появи сесій зв'язування,
  тому в ньому досі показано надсилання Private Key — цей крок більше не потрібен, а все інше в
  ньому не змінилося.

  <div class="video-container">
    <iframe width="380" height="200" src="https://www.youtube.com/embed/JI232HBWHWc" title="Create a linking URL" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" />
  </div>
</Note>

<h3 id="sending-the-linking-url">
  Надсилання URL зв'язування
</h3>

<Warning>
  URL зв'язування авторизує вашого користувача в його профілі, тож ставтеся до нього як до
  пароля. Надсилайте його каналом, якому довіряєте, не записуйте в логи й не передавайте третім
  особам. Він залишається придатним протягом усього свого вікна, тож перезавантаження або
  повторна спроба OAuth працюють — але надсилайте кожне посилання лише одному користувачу і
  створюйте окреме посилання для кожної особи.
</Warning>

### Відкриття URL зв'язування

Відкривайте його у новій вкладці браузера, новому вікні або view controller. Ви можете керувати
[закриттям або перенаправленням](/docs/multiple-users/api-integration-business#opening-&-closing-the-social-linking-url)
цього вікна.

<Note>
  Соціальні мережі не дозволяють відкривати хостовану сторінку зв'язування всередині iFrame або
  приховувати схвалений партнерський origin `profile.ayrshare.com`. Якщо ви хочете, щоб
  зв'язування відбувалося всередині вашої власної сторінки, саме для цього існує
  [вбудований віджет](/docs/multiple-users/connect-widget): його фрейми обслуговуються з origin
  Ayrshare і є підтримуваним способом це зробити.
</Note>

### Як дізнатися, що все завершено

Два сигнали, і можна використовувати будь-який:

* **[Події завершення зв'язування](/docs/multiple-users/link-completion-events)** — задайте `origin`
  під час створення посилання, і вікно зв'язування надсилатиме `connect:success`, `connect:error`
  і `connect:cancelled` на вашу сторінку в міру того, як вони відбуваються. Без опитування.
* **[Отримання Link Session](/docs/apis/profiles/get-link-session)** — повідомляє `completedAt`,
  `lastCompletedAt` і `completedNetworks`. Це сигнал для нативних застосунків і єдиний для
  Telegram, який завершує підключення поза основним потоком.

<h2 id="jwt-expires-in">
  Строк дії посилання
</h2>

Посилання дійсне **5 хвилин** за замовчуванням. Після цього створіть нове.

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

З Max Pack задайте `expiresIn` у хвилинах, щоб розширити це вікно — до **2880 хвилин
(48 годин)**, що є максимумом, який приймає API:

```json Expires In theme={"system"}
{
  "expiresIn": 30
}
```

Саме довше вікно робить [надсилання посилання електронною поштою](#connect-accounts-email)
практичним — користувач, який повторно підключає відв'язаний акаунт, може перейти з вашого листа
прямо до мережі, не відвідуючи спершу ваш застосунок.

<Warning>
  Обговоріть зі своєю командою безпеки, як довго посилання має залишатися активним. Довше вікно —
  це довший період, протягом якого перехоплене посилання все ще працює. Якщо посилання потрапило
  не в ті руки, ви можете [відкликати його](/docs/apis/profiles/revoke-link-session), а не чекати
  завершення строку дії.
</Warning>

## Profile Key

`Profile-Key` визначає, для якого User Profile призначене посилання. Знайти його можна в панелі
розробника Ayrshare, перемкнувшись на цей профіль.

<Note>
  **Private Key більше не використовується.** Посилання не підписуються, тож немає чого читати з
  файлу чи вставляти у ваш код. Застарілий параметр `privateKey` досі приймається й ігнорується,
  тому наявні інтеграції продовжують працювати, а файл `private.key` у вашому Integration Package
  можна не використовувати.
</Note>

## Перемикання профілів

Якщо профіль уже авторизований, відкриття посилання іншого профілю не перемикає профілі — це
зроблено навмисно й забезпечує швидкий досвід для користувача, який уже там. Щоб примусово
перемкнути профіль, див.
[Automatic Logout of a Profile Session](/docs/multiple-users/api-integration-business#automatic-logout-of-a-profile-session).

<h2 id="instagram-link-method">
  Instagram Link Method
</h2>

Акаунти Instagram можна прив'язати [двома способами](/docs/dashboard/connect-social-accounts/instagram):
безпосередньо через **Instagram Login** або через **підключену Facebook Page**. Який процес
починається, коли користувач натискає кнопку Instagram, зазвичай контролюється налаштуванням
[Instagram Login](/docs/multiple-users/manage-user-profiles#instagram-login) на рівні акаунту.

Параметр тіла `instagramLinkMethod` перевизначає це налаштування для окремого посилання:

| Значення | Процес прив'язки Instagram |
| - | - |
| `instagram` | Пряме входження в Instagram. Facebook Page не потрібна. |
| `facebook` | Прив'язка через підключену Facebook Page. |

```json Instagram Link Method theme={"system"}
{
  "instagramLinkMethod": "instagram"
}
```

Перевизначення діє протягом усього життя цього посилання, включно з перенаправленням авторизації
Instagram/Facebook. Кілька моментів, які варто знати:

* Воно не змінює налаштування на рівні акаунту й не впливає на жодне інше посилання.
* Якщо його пропустити, застосовується налаштування на рівні акаунту, як і раніше.
* Недійсне значення повертає `400` зі списком допустимих значень (`instagram`, `facebook`).
* Перегляньте
  [відмінності функцій](/docs/multiple-users/manage-user-profiles#direct-instagram-login-vs-facebook-page-authentication)
  перед вибором — деякі функції Instagram, такі як пошук хештегів і колаборації, доступні лише за
  автентифікації через Facebook Page.

<h2 id="connect-accounts-email">
  Connect Accounts Email
</h2>

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

Ayrshare може надіслати посилання вашому користувачу електронною поштою за вас, щоб він міг
потрапити на свою сторінку зв'язування, не відвідуючи ваш застосунок. Поєднуйте це з довшим
[`expiresIn`](#jwt-expires-in) — стандартні п'ять хвилин рідко переживають поштову скриньку.

### Connect Accounts JSON

**Кожне поле всередині `email` обов'язкове.** Відсутність будь-якого зриває надсилання.

```json Example Contact Email Request theme={"system"}
{
  "expiresIn": 60,
  "email": {
    "to": "john@user.com",
    "contactEmail": "support@mycompany.com",
    "company": "ACME",
    "termsUrl": "https://www.ayrshare.com/terms",
    "privacyUrl": "https://www.ayrshare.com/privacy"
  }
}
```

<Warning>
  `expiresIn` — параметр **верхнього рівня**, а не частина об'єкта `email`. Вкладений в `email`,
  він ігнорується, і ваш користувач отримує посилання, строк дії якого спливає за п'ять хвилин.
</Warning>

Відповідь повідомляє результат у полі `emailSent`:

```json Example Contact Email Response theme={"system"}
{
  "status": "success",
  "sessionId": "c7a2434e72e91bde27579efde0fd6dd0b74ceee29a471fd368407f273708c2e8",
  "url": "https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=YOUR_DOMAIN",
  "expiresAt": "2026-09-02T09:03:26.838Z",
  "emailSent": true,
  "title": "Acme Client"
}
```

Якщо email не вдалося надіслати, запит усе одно успішний і ви отримуєте посилання. Відповідь містить `emailSent: false` і об'єкт `emailError`, тож ви можете передати посилання користувачу іншим способом:

```json Example Failed Email Response theme={"system"}
{
  "status": "success",
  "sessionId": "c7a2434e72e91bde27579efde0fd6dd0b74ceee29a471fd368407f273708c2e8",
  "url": "https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=YOUR_DOMAIN",
  "expiresAt": "2026-09-02T09:03:26.838Z",
  "emailSent": false,
  "emailError": {
    "code": 333,
    "message": "Email failed to send. Please confirm a valid email was provided."
  },
  "title": "Acme Client"
}
```

`emailError` з'являється щоразу, коли ви запитали email, але його не надіслали: або надсилання не вдалося, або в об'єкті `email` бракувало обов'язкового поля, і тоді `details` називає відсутні поля. `emailSent: false` без `emailError` означає, що email не запитували. Якщо немає `to`, ситуація інша: увесь запит відхиляється з `code: 188`.

### Приклад Connect Accounts Email

Ось приклад електронного листа, що відкриває сторінку соціального зв'язування:

<img src="https://mintcdn.com/ayrshare-docs/Nmrhj2Gh7WSf62Bh/images/apis/profiles/jwt-email.webp?fit=max&auto=format&n=Nmrhj2Gh7WSf62Bh&q=85&s=fbe4ee86ca59c26a5bd5b289fda96b8b" alt="Connect Accounts email" width="563" class="center" data-path="images/apis/profiles/jwt-email.webp" />

Лист надійде з адреси:

`Social Connect Hub <connect@socialconnecthub.com>`

<h2 id="mobile-jwt">
  Мобільні застосунки
</h2>

Відкривайте URL зв'язування в **системному браузері**, ніколи не у вбудованому webview: Google
відхиляє вхід у ньому з `disallowed_useragent`, а Meta блокує його повністю. Ваш користувач
побачить власну сторінку помилки мережі, і ніщо на вашому боці цього не виправить.

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

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

<h3 id="mobile-code-examples">
  Приклади мобільного коду
</h3>

Замініть `linkingURL` на `url`, повернений із
[Створення Link Session](/docs/apis/profiles/create-link-session).

<CodeGroup>
  ```swift Swift theme={"system"}
  import UIKit
  import SafariServices

  class ViewController: UIViewController, SFSafariViewControllerDelegate {

      var linkingURL = "https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=acme"

      override func viewDidLoad() {
          super.viewDidLoad()
          setupButton()
      }

      func setupButton() {
          let button = UIButton(type: .system)
          button.frame = CGRect(x: (view.bounds.width - 200) / 2, y: (view.bounds.height - 50) / 2, width: 200, height: 50)
          button.setTitle("Open URL", for: .normal)
          button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
          view.addSubview(button)
      }

      @objc func buttonTapped() {
          openURLInInAppBrowser()
      }

      func openURLInInAppBrowser() {
          if let url = URL(string: linkingURL) {
              let safariVC = SFSafariViewController(url: url)
              safariVC.delegate = self
              present(safariVC, animated: true, completion: nil)
          }
      }

      // Optional: If you want to handle when the in-app browser is closed
      func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
          controller.dismiss(animated: true, completion: nil)
      }
  }
  ```

  ```dart Flutter theme={"system"}
  /** yaml dependencies
    dependencies:
      flutter:
        sdk: flutter
      url_launcher: ^6.2.1
  */

  import 'package:flutter/material.dart';
  import 'package:url_launcher/url_launcher.dart';

  void main() {
    runApp(MyApp());
  }

  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'URL Launcher Example',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      );
    }
  }

  class MyHomePage extends StatelessWidget {
    final String linkingURL = "https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=acme";

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text('URL Launcher Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              openURLInBrowser(context);
            },
            child: Text('Open URL'),
          ),
        ),
      );
    }

    void openURLInBrowser(BuildContext context) async {
      if (await canLaunch(linkingURL)) {
        await launch(linkingURL);
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Could not launch $linkingURL'),
          ),
        );
      }
    }
  }
  ```

  ```jsx React Native theme={"system"}
  /**
  • Using the API provided by expo-web-browser,
  • which opens a URL in a modal browser window that shares cookies
  • with the system browser.

  • Learn more about expo: https://reactnative.dev/docs/environment-setup?guide=quickstart
  • and running the following command:
  • expo install expo-web-browser
  */

  import React from 'react';
  import { StyleSheet, Button, View } from 'react-native';
  import * as WebBrowser from 'expo-web-browser';

  export default function App() {
    const linkingURL = 'https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=acme';

    const openURLInBrowser = async () => {
      try {
        await WebBrowser.openBrowserAsync(linkingURL);
        // Optional: WebBrowser.openBrowserAsync returns a promise that resolves with an object containing
        // 'type' that can be 'cancelled' or 'dismissed'. You can use this to handle when the browser is closed.
      } catch (error) {
        console.error(error);
      }
    };

    return (
      <View style={styles.container}>
        <Button title="Open URL" onPress={openURLInBrowser} />
      </View>
    );
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
    },
  });
  ```
</CodeGroup>

## Тестування

**Рекомендується** спочатку створити посилання в [Postman](/docs/testing/postman). Ваш Integration
Package — на сторінці API Key основного профілю (Primary Profile) в панелі керування — містить
зразкову конфігурацію Postman. Імпортуйте її, заповніть свій Profile Key у полі *body*
`profileKey` і натисніть *Send*.

Зразкова конфігурація досі заповнює `privateKey` і `domain`. `privateKey` ігнорується, а `domain`
можна очистити, якщо ваш акаунт не має більше ніж одного домену зв'язування.

Ви також можете [згенерувати код із Postman](/docs/testing/postman#auto-generate-api-code-with-postman).

### Bubble.io

<Card title="Bubble linking URL" icon="link" href="/docs/packages-guides/bubble#generate-a-linking-url-in-bubble" horizontal />

## Legacy: generateJWT

<Info>
  [Генерація URL для підключення](/docs/apis/profiles/generate-jwt) (`generateJWT`) виконує ту саму
  роботу і є **застарілою** — повністю підтримується, не має дати вилучення і працює без змін для
  посилань, які ви вже роздали. Її власна сторінка документує параметри, включно з трьома, які
  тепер приймаються й ігноруються.

  Обидва ендпоінти використовують той самий валідатор, тож усе на цій сторінці стосується
  будь-якого з них. Одна відмінність, яку варто знати під час міграції: `generateJWT` терпить три
  речі, які Створення Link Session відхиляє — нерозпізнану мережу в `allowedSocial`, лише одну
  половину облікових даних X і нерядковий `redirect`.
</Info>


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