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

> أنشئ عنوان URL لربط الشبكات الاجتماعية لملف مستخدم، دون إرسال مفتاح خاص.

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

export const HeaderAPI = ({noProfileKey, profileKeyRequired}) => <>
    <ParamField header="Authorization" type="string" required>
      <a href="/docs/apis/overview#authorization">API Key</a> of the Primary Profile.
      <br />
      <br />
      Format: <code>Authorization: Bearer API_KEY</code>
    </ParamField>
    {!noProfileKey && (profileKeyRequired ? <ParamField header="Profile-Key" type="string" required>
          <a href="/docs/apis/overview#profile-key-format">Profile Key</a> of a User Profile.
          <br />
          <br />
          Format: <code>Profile-Key: PROFILE_KEY</code>
        </ParamField> : <ParamField header="Profile-Key" type="string">
          <a href="/docs/apis/overview#profile-key-format">Profile Key</a> of a User Profile.
          <br />
          <br />
          Format: <code>Profile-Key: PROFILE_KEY</code>
        </ParamField>)}
  </>;

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

أنشئ عنوان URL لربط الشبكات الاجتماعية لـ User Profile (ملف مستخدم). أرسل `url` المُعاد إلى
مستخدمك، فيفتحه لربط حساباته الاجتماعية.

هذه هي الطريقة الموصى بها لإنشاء رابط ربط. فهي لا تحتاج إلا إلى مفتاح API الخاص بك
و`Profile-Key` — لا يوجد مفتاح خاص يُرسل ولا شيء يُوقَّع. وعلى خلاف رابط الربط المُنشأ
سابقًا، تُخزَّن Link Session، لذا يمكنك التحقق مما إذا كانت قد استُخدمت وإبطالها قبل انتهاء
صلاحيتها.

يُسجّل `url` المُعاد دخول مستخدمك إلى ملفه، لذا تعامل معه كما تتعامل مع كلمة المرور وأرسل
كل واحد إلى مستخدم واحد فقط. راجع
[إرسال رابط الربط](/docs/apis/profiles/social-linking-overview#sending-the-linking-url).

<Note>
  عنوان URL صالح لمدة **5 دقائق** افتراضيًا. استخدم `expiresIn` لتحديد نافذة زمنية مختلفة،
  حتى 2880 دقيقة (48 ساعة).
</Note>

<Info>
  تنفّذ [إنشاء رابط ربط (generateJWT)](/docs/apis/profiles/generate-jwt) العملية نفسها وتستمر في
  العمل دون تغيير. فهي تقبل المعاملات القديمة `privateKey` و`base64` و`verify` وتتجاهلها.
  أما `domain` فلا يُتجاهل في أيٍّ من نقطتي النهاية — يبقى اختياريًا ولا يزال يُتحقق منه.
  ينبغي للتكاملات الجديدة استخدام نقطة النهاية هذه.

  ثمة فرق واحد في الاستجابة: يُعيد `generateJWT` حقل `token` في المستوى الأعلى للتوافق مع
  الإصدارات السابقة، بينما لا تُعيده نقطة النهاية هذه **إلى جانب** `url` — فالتوكن في `url`
  يعيش داخله. إذا كنت تنتقل إلى نقطة النهاية هذه وكانت تعليماتك البرمجية تقرأ `token`، فاقرأ
  `url` بدلًا منه. ([وضع Connect](#connect-mode) الخاص بالأداة المضمّنة هو الشكل الوحيد الذي
  يعيد `token` مجردًا، لأنه لا يعيد عنوان URL يعيش التوكن فيه.)
</Info>

## معاملات الترويسة

<HeaderAPI profileKeyRequired={true} />

<Note>
  `Profile-Key` ترويسة في نقطة النهاية هذه — لا يوجد معامل جسم `profileKey`. إذا كانت
  مفقودة تحصل على `code: 188`، الذي تسرد رسالته `privateKey` و`profileKey` وأسماء حقول
  قديمة أخرى لأنه مشترك مع
  [إنشاء رابط ربط (generateJWT)](/docs/apis/profiles/generate-jwt). اقرأه على أنه "ترويسة
  Profile-Key مفقودة أو خاطئة"؛ فلا شيء من الأسماء الأخرى الواردة فيه هو معامل لنقطة
  النهاية هذه.
</Note>

<ParamField header="X-Twitter-OAuth1-Api-Key" type="string">
  مفتاح X API الخاص بك (Consumer Key) من X Developer Portal. عند تزويده، سيستخدم رابط
  الربط تطبيق X Developer الخاص بك في ربط OAuth.
</ParamField>

<ParamField header="X-Twitter-OAuth1-Api-Secret" type="string">
  X API Secret الخاص بك (Consumer Secret) من X Developer Portal. مطلوب عند تزويد
  `X-Twitter-OAuth1-Api-Key`.
</ParamField>

## معاملات الجسم

<ParamField body="mode" type="string" default="grid">
  سطح الربط الذي تشغّله هذه الجلسة.

  * `grid` — صفحة الربط المستضافة، تعرض كل شبكة تسمح بها. هذا هو الافتراضي، فالطلب الذي
    يُغفل `mode` ينشئ واحدة منها.
  * `connect` — شبكة واحدة في كل مرة، تُفتح من لوحة التحكم الخاصة بك. راجع
    [وضع Connect](#connect-mode) أدناه و[الوضع المباشر](/docs/multiple-users/connect-direct-mode).

  لا يُستنتج أبدًا: تمرير `origin` أو `network` لا يضعك في وضع connect، فلا يمكن لجلسة grid
  أن تتحول إلى جلسة مقيّدة عن غير قصد. أي قيمة أخرى تعيد `code: 188` مع `details` يُسمّي
  القيمتين.
</ParamField>

<ParamField body="expiresIn" type="number" default={5}>
  مدة صلاحية الرابط بالدقائق. النطاق: من 1 إلى 2880 دقيقة.

  يتطلب Max Pack.

  انظر [انتهاء صلاحية الرابط](/docs/apis/profiles/social-linking-overview#jwt-expires-in) لمزيد من المعلومات.
</ParamField>

<ParamField body="logout" type="boolean" default={false}>
  تسجيل الخروج التلقائي من الجلسة الحالية. لا يُنصح به في بيئة الإنتاج لأنه يؤثر على
  الأداء.

  انظر [تسجيل الخروج التلقائي من جلسة الملف الشخصي](/docs/multiple-users/api-integration-business#automatic-logout-of-a-profile-session).
</ParamField>

<ParamField body="redirect" type="string">
  عنوان URL لإعادة التوجيه إليه عند النقر على زر "Done" (تم) أو صورة الشعار. أضف معامل
  الاستعلام `origin=true` لإعادة توجيه نافذة الأصل الفاتحة.
</ParamField>

<ParamField body="allowedSocial" type="array">
  الشبكات الاجتماعية المراد عرضها في صفحة الربط. يتجاوز الشبكات المُهيَّأة في صفحة
  [Social Networks](/docs/multiple-users/manage-user-profiles#set-social-networks-access).

  ```json Only display Facebook, X/Twitter, LinkedIn, and TikTok theme={"system"}
  {
    "allowedSocial": ["facebook", "twitter", "linkedin", "tiktok"]
  }
  ```
</ParamField>

<ParamField body="network" type="string">
  لوضع connect فقط. الشبكة الاجتماعية الواحدة التي تربطها هذه الجلسة، وهي ما يجعلها جلسة
  **وضع مباشر**. أغفلها لجلسة تشغّلها لوحة التحكم الخاصة بك عبر عدة شبكات.

  واحدة من `bluesky` أو `facebook` أو `gmb` أو `instagram` أو `instagramApi` أو `linkedin`
  أو `pinterest` أو `reddit` أو `snapchat` أو `telegram` أو `threads` أو `tiktok` أو
  `twitter` أو `whatsapp` أو `x` أو `youtube`. أي شيء آخر يعيد `code: 508` — بما في ذلك
  `fbg`، الذي ليس هدف ربط هنا.

  لا يمكن جمعه مع `allowedSocial` (يعيد `code: 507`): فجلسة الشبكة الواحدة هي قائمة السماح
  الخاصة بها بالفعل. الشبكة التي لم يفعّلها حسابك تعيد `code: 509`، وهو جواب مختلف عن 508
  لأنه قابل للإصلاح في صفحة
  [Social Networks](/docs/multiple-users/manage-user-profiles#set-social-networks-access) لديك.

  في وضع grid يُتجاهل.
</ParamField>

<ParamField body="instagramLinkMethod" type="string">
  تجاوز تدفق ربط Instagram المستخدم لهذا الرابط. القيم الصالحة:

  * `instagram`: تسجيل دخول Instagram المباشر، دون الحاجة إلى Facebook Page.
  * `facebook`: ربط Instagram عبر Facebook Page متصلة.

  إذا حُذف، تستخدم صفحة الربط إعداد
  [Instagram Login](/docs/multiple-users/manage-user-profiles#instagram-login) على مستوى حسابك.
</ParamField>

<ParamField body="origin" type="string">
  الأصل الفعلي للصفحة التي فتحت نافذة الربط، حتى يمكن إخبارها عند اكتمال الربط.

  عند ضبطه، ترسل صفحة الربط أحداثًا إلى ذلك الأصل عبر `window.postMessage` مع ربط مستخدمك
  كل حساب، فتستطيع صفحتك التفاعل دون استطلاع. لا تُرسل الأحداث أبدًا إلا إلى هذه القيمة
  بالضبط، لذا يجب أن تطابق أصل صفحتك حرفًا بحرف، بما في ذلك المخطط (scheme) وأي منفذ.

  تُقبل ثلاثة أشكال: أصل `https`‏ (`https://app.example.com`)، و`http://localhost:3000`
  للتطوير المحلي، ومخطط مخصص أصلي (`myapp://connected`). أي شيء آخر — أصل `http://` عادي
  غير localhost، أو شيء ليس أصلًا إطلاقًا — يُتجاهل على الروابط التي تنشئها نقطة النهاية
  هذه: يظل الرابط يعمل، لكنه ببساطة لا يرسل أي أحداث. وهو اختياري، فإغفاله ليس خطأً أيضًا.

  من الأشكال الثلاثة، لا يتلقى الأحداث إلا الأولان. المخطط المخصص هدف عودة لتطبيق محمول
  و**لا يمكنه تلقّيها**، لأنه لا توجد نافذة متصفح تُرسل إليها؛ تستطلع التطبيقات الأصلية
  [الحصول على Link Session](/docs/apis/profiles/get-link-session) بدلًا من ذلك.

  راجع [أحداث اكتمال الربط](/docs/multiple-users/link-completion-events).

  **في وضع connect يكون `origin` مطلوبًا، ويجري التحقق منه.** التساهل أعلاه هو سلوك وضع
  grid. مع `mode: "connect"`، يعيد إغفاله `code: 505`، وتعيد القيمة التي ليست أحد الأشكال
  الثلاثة المقبولة `code: 506`، الذي يكرّر `details` فيه الشكل الذي أرسلته.
</ParamField>

<ParamField body="domain" type="string">
  اختياري. نطاق الربط الخاص بك، عندما يكون لحسابك أكثر من نطاق واحد. إذا أُغفل، يُستخدم
  نطاق حسابك نفسه. ويُرفض أي نطاق غير مسجّل على حسابك.
</ParamField>

<ParamField body="email" type="object">
  أرسل بريد Connect Accounts يحمل الرابط، ليتمكن مستخدمك من الوصول مباشرةً إلى صفحة
  الربط الخاصة به. يتطلب عنوان `to`.

  يتطلب Max Pack. تُبلّغ الاستجابة عن النتيجة في `emailSent`، ويُعيد فشل الإرسال
  `code: 333` بدلًا من استجابة نجاح.

  انظر [بريد Connect Accounts](/docs/apis/profiles/social-linking-overview#connect-accounts-email).
</ParamField>

<h2 id="connect-mode">
  وضع Connect
</h2>

يُنشئ `mode: "connect"` جلسة لسطح ربط تستضيفه أنت بنفسك، لا لصفحة الربط المستضافة. أما أي
شكلي connect تحصل عليه فيعتمد على أمر واحد — هل مرّرت `network` أم لا:

| ما ترسله                         | ما يُعاد إليك                        | ما تفعله به                                                                         |
| -------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------- |
| `mode: "connect"` مع `network`   | ‏`url` يشير إلى صفحة ربط لشبكة واحدة | افتحه في نافذة منبثقة — هذا هو [الوضع المباشر](/docs/multiple-users/connect-direct-mode) |
| `mode: "connect"` بدون `network` | ‏`token`، وبلا عنوان URL إطلاقًا     | سلّمه إلى واجهتك الأمامية                                                           |

<Note>
  **تحمل الاستجابة السر مرة واحدة بالضبط.** للاستجابة إما `url` أو `token`، وليس الاثنين
  أبدًا ولا عنوانا URL اثنان أبدًا. يعيش التوكن في جلسة الوضع المباشر داخل `url`، تمامًا كما
  في وضع grid؛ أما الجلسة التي لا تملك عنوان URL يحمله فتعيد `token` مجردًا بدلًا من ذلك. كل
  ما عدا ذلك هو نفسه في الأوضاع الثلاثة: `sessionId` و`expiresAt` و`emailSent`، و`title`
  عندما يكون لـ User Profile واحد.
</Note>

### ما يتطلبه وضع Connect

لا شيء من هذين حقل جسم مستقل — فالأول استحقاق على مستوى الحساب والثاني هو معامل
[`origin`](#body-parameters) أعلاه، الذي يجعله وضع connect إلزاميًا.

**[Max Pack](/docs/additional/maxpack).** من دونه يعيد الاستدعاء `code: 504`، ويُفحص قبل معاملات
وضع connect، لذا فإن تصحيح `origin` أو `network` لن يغيّر الجواب. تواصل مع الدعم إذا كنت
بحاجة إلى تفعيل وضع connect على حساب من دون Max Pack.

**`origin`، على كل جلسة.** لا توجد قائمة سماح ولا خطوة تسجيل — ترسله مع كل استدعاء ويُخزَّن
على الجلسة، فلا تحتاج بيئة جديدة إلى أي إعداد من جانبنا. تُقبل ثلاثة أشكال:

* أصل `https` — ‏`https://app.example.com`
* مخطط مخصص أصلي — ‏`myapp://connected`
* ‏`http://localhost` أو `http://localhost:3000`، للتطوير المحلي

الأصل فقط: بلا مسار ولا استعلام ولا جزء (fragment)، وبلا بيانات اعتماد فيه. إغفاله يعيد
`code: 505`، وأي شيء ليس أحد الأشكال الثلاثة يعيد `code: 506`.

<Warning>
  لا يمكن استخدام `email` مع جلسة لا تملك `network`، لأنه لا يوجد رابط يوضع في البريد
  الإلكتروني — فهذا الشكل يعيد توكنًا لواجهتك الأمامية. يعيد الاستدعاء `code: 510`. أضف
  `network` لجلسة وضع مباشر، التي تملك عنوان URL بالفعل، أو أغفل `email`.
</Warning>

كل رمز مُسمّى أعلاه موجود في مرجع
[أخطاء Link Session](/docs/errors/errors-ayrshare#link-session-errors).

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

  ```javascript JavaScript theme={"system"}
  const API_KEY = "API_KEY";
  const PROFILE_KEY = "PROFILE_KEY";

  fetch("https://api.ayrshare.com/api/profiles/link-sessions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${API_KEY}`,
      "Profile-Key": PROFILE_KEY,
    },
    body: JSON.stringify({ expiresIn: 60 }),
  })
    .then((res) => res.json())
    .then((json) => console.log(json))
    .catch(console.error);
  ```

  ```python Python theme={"system"}
  import requests

  payload = {'expiresIn': 60}
  headers = {'Content-Type': 'application/json',
          'Authorization': 'Bearer API_KEY',
          'Profile-Key': 'PROFILE_KEY'}

  response = requests.post('https://api.ayrshare.com/api/profiles/link-sessions',
                           json=payload, headers=headers)
  print(response.json())
  ```

  ```php PHP theme={"system"}
  <?php
  require 'vendor/autoload.php';    // Composer auto-loader using Guzzle. See .../guzzlephp.org/en/stable/overview.html

  $client = new GuzzleHttp\Client();
  $res = $client->request(
      'POST',
      'https://api.ayrshare.com/api/profiles/link-sessions',
      [
          'headers' => [
              'Content-Type'  => 'application/json',
              'Authorization' => 'Bearer API_KEY',
              'Profile-Key'   => 'PROFILE_KEY'
          ],
          'json' => [
              'expiresIn' => 60,
          ]
      ]
  );

  echo json_encode(json_decode($res->getBody()), JSON_PRETTY_PRINT);
  ```

  ```csharp C# theme={"system"}
  using System;
  using System.Net.Http;
  using System.Text;
  using System.Threading.Tasks;
  using Newtonsoft.Json;

  namespace CreateLinkSession_csharp
  {
    class CreateLinkSession
    {
        static async Task Main(string[] args)
        {
            string API_KEY = "API_KEY";
            string PROFILE_KEY = "PROFILE_KEY";
            string url = "https://api.ayrshare.com/api/profiles/link-sessions";

            try
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_KEY);
                    client.DefaultRequestHeaders.Add("Profile-Key", PROFILE_KEY);

                    var sendData = new { expiresIn = 60 };
                    string jsonData = JsonConvert.SerializeObject(sendData);
                    var content = new StringContent(jsonData, Encoding.UTF8, "application/json");

                    HttpResponseMessage response = await client.PostAsync(url, content);
                    response.EnsureSuccessStatusCode();

                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(responseBody);
                }
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine($"HTTP request error: {e.Message}");
            }
        }
    }
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={"system"}
  {
      "status": "success",
      "sessionId": "c7a2434e72e91bde27579efde0fd6dd0b74ceee29a471fd368407f273708c2e8",  // Identifier for this link. Use it with Get and Revoke a Link Session.
      "url": "https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=YOUR_DOMAIN",  // Send this to your user exactly as returned. The token exists only in here.
      "expiresAt": "2026-09-02T08:03:26.838Z",  // When the link stops working, as an ISO 8601 timestamp.
      "emailSent": false,  // Whether the connect-accounts email was sent. false means none was requested; a send failure returns code: 333 instead.
      "title": "Acme Client"  // The User Profile's title. Omitted when the profile has none.
  }
  ```

  ```json 200: Direct Mode (mode: "connect" with a network) theme={"system"}
  {
      "status": "success",
      "sessionId": "c7a2434e72e91bde27579efde0fd6dd0b74ceee29a471fd368407f273708c2e8",
      "url": "https://profile.ayrshare.com/connect?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu",  // Open this in a popup. One network, no domain parameter.
      "expiresAt": "2026-09-02T08:03:26.838Z",
      "emailSent": false,
      "title": "Acme Client"
  }
  ```

  ```json 200: Connect Mode Without a Network theme={"system"}
  {
      "status": "success",
      "sessionId": "c7a2434e72e91bde27579efde0fd6dd0b74ceee29a471fd368407f273708c2e8",
      "token": "ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu",  // No url: this shape returns the bare token instead. Treat it like a password.
      "expiresAt": "2026-09-02T08:03:26.838Z",
      "emailSent": false,  // Always false here - email needs a link to send, so it returns code: 510.
      "title": "Acme Client"
  }
  ```

  ```json 401: Connect Mode Requires the Max Pack theme={"system"}
  {
    "action": "link session",
    "status": "error",
    "code": 504,
    "message": "Connect mode requires the Max Pack. Activate it on your Account page: https://app.ayrshare.com/account"
  }
  ```

  ```json 400: Missing Profile-Key Header theme={"system"}
  {
    "action": "JWT",
    "status": "error",
    "code": 188,
    "message": "Missing or incorrect privateKey, profileKey, domain, email 'to', or expiresIn fields."
  }
  ```

  ```json 400: Domain Not Registered to Your Account theme={"system"}
  {
    "action": "JWT",
    "status": "error",
    "code": 189,
    "message": "Error generating JWT. Check the sent parameters.",
    "details": "Missing or incorrect domain."
  }
  ```

  ```json 403: expiresIn Requires the Max Pack theme={"system"}
  {
    "action": "JWT",
    "status": "error",
    "code": 340,
    "message": "Max Pack required. Go to your dashboard to add the Max Pack."
  }
  ```
</ResponseExample>
