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

# Create a Link Session

> Create a social-linking URL for a user profile, without sending a private key.

Create a social-linking URL for a User Profile. Send the returned `url` to your user, and
they open it to connect their social accounts.

This is the recommended way to create a linking URL. It needs only your API key and a
`Profile-Key` — there is no private key to send and nothing to sign. Unlike a linking
URL created before, a link session is stored, so you can check whether it has been used
and revoke it before it expires.

The returned `url` signs your user into their profile, so treat it like a password and send
each one to a single user. See
[Sending the Linking URL](https://www.ayrshare.com/docs/apis/profiles/social-linking-overview.md#sending-the-linking-url).

> [!NOTE]
>
> The URL is valid for **5 minutes** by default. Use `expiresIn` to set a different
> window, up to 2880 minutes (48 hours).

> [!NOTE]
>
> [Generate a Linking URL](https://www.ayrshare.com/docs/apis/profiles/generate-jwt.md) performs the same operation and keeps
> working unchanged. It accepts the legacy `privateKey`, `base64` and `verify` parameters
> and ignores them. `domain` is not ignored on either endpoint - it stays optional and is
> still validated. New integrations should use this endpoint.
>
> One difference in the response: `generateJWT` returns a top-level `token` for backwards
> compatibility, and this endpoint does not return one **alongside** a `url` — the token in a
> `url` lives inside it. If you are migrating and your code reads `token`, read `url` instead.
> ([Connect mode](#connect-mode) for the embedded widget is the one shape that returns a bare
> `token`, because it returns no URL for the token to live in.)

## Header Parameters

**Authorization** `string` *required*

[API Key](https://www.ayrshare.com/docs/apis/overview.md#authorization) of the Primary Profile.

Format: `Authorization: Bearer API_KEY`
**Profile-Key** `string` *required*

[Profile Key](https://www.ayrshare.com/docs/apis/overview.md#profile-key-format) of a User Profile.

Format: `Profile-Key: PROFILE_KEY`

> [!NOTE]
>
> The `Profile-Key` is a header on this endpoint — there is no `profileKey` body
> parameter. If it is missing you get `code: 188`, whose message lists `privateKey`,
> `profileKey` and other legacy field names because it is shared with
> [Generate a Linking URL](https://www.ayrshare.com/docs/apis/profiles/generate-jwt.md). Read it as "the Profile-Key header is
> missing or wrong"; none of the other names in it are parameters of this endpoint.

**X-Twitter-OAuth1-Api-Key** `string`

Your X API Key (Consumer Key) from the X Developer Portal. When provided, the linking
URL will use your own X Developer App for OAuth linking.

**X-Twitter-OAuth1-Api-Secret** `string`

Your X API Secret (Consumer Secret) from the X Developer Portal. Required when
`X-Twitter-OAuth1-Api-Key` is provided.

## Body Parameters

**mode** `string` (default: grid)

Which linking surface this session drives.

* `grid` — the hosted linking page, showing every network you permit. This is the default, so a
  request that omits `mode` creates one.
* `connect` — one network at a time, opened from your own dashboard. See
  [Connect Mode](#connect-mode) below and [Direct Mode](https://www.ayrshare.com/docs/multiple-users/connect-direct-mode.md).

Never inferred: passing `origin` or `network` does not put you in connect mode, so a grid
session cannot become a gated one by accident. Any other value returns `code: 188` with
`details` naming the two.

**expiresIn** `number` (default: 5)

Longevity of the link in minutes. Range: 1 to 2880 minutes.

Requires the Max Pack.

See [Link Expiry](https://www.ayrshare.com/docs/apis/profiles/social-linking-overview.md#jwt-expires-in) for more information.

**logout** `boolean` (default: false)

Automatically log out the current session. Not recommended in production, since it
affects performance.

See [Automatic Logout of a Profile Session](https://www.ayrshare.com/docs/multiple-users/api-integration-business.md#automatic-logout-of-a-profile-session).

**redirect** `string`

A URL to redirect to when the "Done" button or logo image is clicked. Add the query
parameter `origin=true` to redirect the opener window.

**allowedSocial** `array`

The social networks to display on the linking page. Overrides the networks configured
on the [Social Networks](https://www.ayrshare.com/docs/multiple-users/manage-user-profiles.md#set-social-networks-access)
page.

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

**network** `string`

Connect mode only. The single social network this session connects, which is what makes it a
**direct-mode** session. Omit it for a session your own dashboard drives across several
networks.

One of `bluesky`, `facebook`, `gmb`, `instagram`, `instagramApi`, `linkedin`, `pinterest`,
`reddit`, `snapchat`, `telegram`, `threads`, `tiktok`, `twitter`, `whatsapp`, `x`, `youtube`.
Anything else returns `code: 508` — including `fbg`, which is not a link target here.

Cannot be combined with `allowedSocial` (`code: 507`): a single-network session is already its
own allowlist. A network your account has not enabled returns `code: 509`, which is a different
answer from 508 because it is fixable on your
[Social Networks](https://www.ayrshare.com/docs/multiple-users/manage-user-profiles.md#set-social-networks-access) page.

In grid mode it is ignored.

**instagramLinkMethod** `string`

Override which Instagram linking flow is used for this link. Valid values:

* `instagram`: Direct Instagram Login, no Facebook Page required.
* `facebook`: Link Instagram via a connected Facebook Page.

When omitted, the linking page uses your account-wide
[Instagram Login](https://www.ayrshare.com/docs/multiple-users/manage-user-profiles.md#instagram-login) setting.

**origin** `string`

The exact origin of the page that opened the linking window, so it can be told when
linking finishes.

When set, the linking page posts events to that origin with `window.postMessage` as
your user connects each account, and your page can react without polling. Events are
only ever sent to this exact value, so it must match your page's origin character for
character, including the scheme and any port.

Three shapes are accepted: an `https` origin (`https://app.example.com`),
`http://localhost:3000` for local development, and a native custom scheme
(`myapp://connected`). Anything else — a plain `http://` origin other than localhost, or
something that is not an origin at all — is ignored on the links this endpoint creates:
the link still works, it simply sends no events. It is optional, so omitting it is not an
error either.

Of the three, only the first two receive events. A custom scheme is a return target for
a mobile app and **cannot receive them**, because there is no browser window to post to;
native apps poll [Get a Link Session](https://www.ayrshare.com/docs/apis/profiles/get-link-session.md) instead.

See [Link Completion Events](https://www.ayrshare.com/docs/multiple-users/link-completion-events.md).

**In connect mode `origin` is required, and it is checked.** The leniency above is grid-mode
behaviour. With `mode: "connect"`, omitting it returns `code: 505` and a value that is not one
of the three accepted shapes returns `code: 506`, whose `details` repeat the shape you sent.

**domain** `string`

Optional. Your linking domain, when your account has more than one. When omitted, your
account's own domain is used. A domain not registered to your account is rejected.

**email** `object`

Send a Connect Accounts email carrying the link, so your user can reach their linking
page directly. Requires a `to` address.

Requires the Max Pack. The response reports the outcome in `emailSent`. If the email can't be
sent, you still get the link: the response has `emailSent: false` and an `emailError` object, so
you can send the link to your user another way.

See [Connect Accounts Email](https://www.ayrshare.com/docs/apis/profiles/social-linking-overview.md#connect-accounts-email).

## Connect Mode

`mode: "connect"` creates a session for a linking surface you host yourself, rather than for the
hosted linking page. Which of the two connect shapes you get depends on one thing — whether you
pass `network`:

| You send | You get back | What you do with it |
| - | - | - |
| `mode: "connect"` and a `network` | a `url` pointing at a single-network connect page | open it in a popup — this is [direct mode](https://www.ayrshare.com/docs/multiple-users/connect-direct-mode.md) |
| `mode: "connect"` and no `network` | a `token`, and no URL at all | hand it to your own front end |

> [!NOTE]
>
> **The response carries the secret exactly once.** A response has either a `url` or a `token`,
> never both and never two URLs. The token in a direct-mode session lives inside the `url`, the
> same way it does in grid mode; a session with no URL to carry it returns the bare `token`
> instead. Everything else is the same in all three modes: `sessionId`, `expiresAt`, `emailSent`,
> and `title` when the User Profile has one.

### What Connect Mode Requires

Neither of these is a body field of its own — the first is an account entitlement and the second is
the [`origin`](#body-parameters) parameter above, which connect mode makes mandatory.

**The [Max Pack](https://www.ayrshare.com/docs/additional/maxpack.md).** Without it the call returns `code: 504`, checked before
the connect-mode parameters, so correcting `origin` or `network` will not change the answer. Contact support if you
need connect mode enabled on an account without the Max Pack.

**An `origin`, on every session.** There is no allowlist and no registration step — you send it on
each call and it is stored on the session, so a new environment needs no setup on our side. Three
shapes are accepted:

* an `https` origin — `https://app.example.com`
* a native custom scheme — `myapp://connected`
* `http://localhost` or `http://localhost:3000`, for local development

Origin only: no path, query or fragment, and no credentials in it. Omitting it returns `code: 505`,
and anything that is not one of the three shapes returns `code: 506`.

> [!WARNING]
>
> `email` cannot be used with a session that has no `network`, because there is no link to put in
> the email — that shape returns a token for your own front end. The call returns `code: 510`.
> Add a `network` for a direct-mode session, which does have a URL, or omit `email`.

Every code named above is in the [Link Session Errors](https://www.ayrshare.com/docs/errors/errors-ayrshare.md#link-session-errors)
reference.

```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}");
          }
      }
  }
}
```

```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 with no emailError means no email was requested.
    "title": "Acme Client"  // The User Profile's title. Omitted when the profile has none.
}
```

```json 200: Email Failed to Send theme={"system"}
{
    "status": "success",
    "sessionId": "c7a2434e72e91bde27579efde0fd6dd0b74ceee29a471fd368407f273708c2e8",
    "url": "https://profile.ayrshare.com?session=ayr_ls_kJ8mQ2vX9pLnR4tYwZ6aBcD1eFgH3iJkLmN0oPqRsTu&domain=YOUR_DOMAIN",  // Still valid. Send it to your user yourself.
    "expiresAt": "2026-09-02T08:03:26.838Z",
    "emailSent": false,
    "emailError": {  // Only present when an email was requested and could not be sent.
        "code": 333,
        "message": "Email failed to send. Please confirm a valid email was provided."
    },
    "title": "Acme Client"
}
```

```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 401: expiresIn Requires the Max Pack theme={"system"}
{
  "action": "authorization",
  "status": "error",
  "code": 340,
  "message": "Max Pack is required. Please go to your Account page in the Ayrshare Dashboard to activate the Max Pack.",
  "details": "email and expiresIn parameters are only available on the Max Pack."
}
```


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