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
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);
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
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);
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}");
}
}
}
}
{
"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.
}
{
"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"
}
{
"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"
}
{
"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"
}
{
"action": "JWT",
"status": "error",
"code": 188,
"message": "Missing or incorrect privateKey, profileKey, domain, email 'to', or expiresIn fields."
}
{
"action": "JWT",
"status": "error",
"code": 189,
"message": "Error generating JWT. Check the sent parameters.",
"details": "Missing or incorrect domain."
}
{
"action": "JWT",
"status": "error",
"code": 340,
"message": "Max Pack required. Go to your dashboard to add the Max Pack."
}
Profiles
建立 Link Session
為使用者 profile 建立社群帳號連結 URL,無需傳送 private key。
POST
/
profiles
/
link-sessions
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
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);
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
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);
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}");
}
}
}
}
{
"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.
}
{
"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"
}
{
"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"
}
{
"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"
}
{
"action": "JWT",
"status": "error",
"code": 188,
"message": "Missing or incorrect privateKey, profileKey, domain, email 'to', or expiresIn fields."
}
{
"action": "JWT",
"status": "error",
"code": 189,
"message": "Error generating JWT. Check the sent parameters.",
"details": "Missing or incorrect domain."
}
{
"action": "JWT",
"status": "error",
"code": 340,
"message": "Max Pack required. Go to your dashboard to add the Max Pack."
}
為 User Profile 建立社群帳號連結 URL。將回傳的
上面提到的每個錯誤碼都收錄在 Link Session 錯誤
參考中。
url 交給你的使用者,他們開啟後即可連結自己的社群帳號。
這是建立連結 URL 的建議方式。它只需要你的 API Key 和一個 Profile-Key——不需要傳送任何 private key,也沒有任何東西需要簽署。與以往建立的連結 URL 不同,link session 會被儲存下來,因此你可以查詢它是否已被使用,並在過期前撤銷它。
回傳的 url 會讓你的使用者登入到他們的 profile,因此請像對待密碼一樣對待它,且每個 URL 只發給一位使用者。請參閱傳送連結 URL。
該 URL 預設有效期為 5 分鐘。使用
expiresIn 可設定不同的有效期,最長 2880 分鐘(48 小時)。產生連結 URL 執行相同的操作,並且維持不變地繼續運作。它仍接受舊的
privateKey、base64 與 verify 參數並將其忽略。domain 在兩個端點上都不會被忽略——它仍為選填,
且仍會被驗證。新的整合請使用此端點。回應中有一項差異:generateJWT 為了向下相容會回傳頂層的 token,而此端點不會在 url 之外
另行回傳 token——url 中的 token 就在 URL 裡面。如果你正在遷移且程式碼會讀取 token,請改為讀取
url。(供內嵌小工具使用的 Connect 模式是唯一會回傳裸 token 的形態,
因為它不回傳可以承載 token 的 URL。)標頭參數
在此端點上,
Profile-Key 是一個標頭——不存在 profileKey body 參數。若缺少該標頭會得到
code: 188,其訊息會列出 privateKey、profileKey 和其他舊欄位名稱,因為該訊息與
產生連結 URL 共用。請將它理解為「Profile-Key 標頭缺少或有誤」;
訊息中的其他名稱都不是此端點的參數。string
你從 X Developer Portal 取得的 X API Key(Consumer Key)。當提供時,連結 URL 將使用你自己的
X Developer App 進行 OAuth 連結。
string
你從 X Developer Portal 取得的 X API Secret(Consumer Secret)。當提供了
X-Twitter-OAuth1-Api-Key 時為必填。Body 參數
string
預設值:"grid"
此工作階段驅動哪一種連結介面。
grid——代管連結頁面,顯示你允許的每一個網路。這是預設值,因此省略mode的請求會建立 這種工作階段。connect——一次一個網路,從你自己的儀表板開啟。請參閱下方的 Connect 模式 與直接模式。
origin 或 network 並不會讓你進入 connect 模式,因此 grid 工作階段
不會意外變成受限制的工作階段。任何其他值都會回傳 code: 188,其 details 會列出這兩個值。boolean
預設值:false
自動登出目前的工作階段。建議不要在正式環境中使用,因為會影響效能。請參閱自動登出 Profile 工作階段。
string
指定當使用者點擊「Done」(完成)按鈕或 Logo 圖片時要轉向的 URL。加入
origin=true 查詢參數即可轉向
原始開啟者視窗。array
指定要在連結頁面上顯示的社群網路。此設定會覆寫 Social Networks
頁面所設定的社群網路。
Only display Facebook, X/Twitter, LinkedIn, and TikTok
{
"allowedSocial": ["facebook", "twitter", "linkedin", "tiktok"]
}
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 頁面自行修正。在 grid 模式中會被忽略。string
針對此連結,覆寫所使用的 Instagram 連結流程。有效值:
instagram:直接的 Instagram Login,不需 Facebook 粉絲專頁。facebook:透過已連結的 Facebook 粉絲專頁連結 Instagram。
string
開啟連結視窗的頁面的確切來源,讓該頁面能在連結完成時獲得通知。設定後,連結頁面會在使用者連結每個帳號時,以
window.postMessage 向該來源傳送事件,
你的頁面便能即時反應而不必輪詢。事件只會傳送到這個確切的值,因此它必須與你頁面的來源逐字元
相符,包括 scheme 與任何連接埠。接受三種形態:https 來源(https://app.example.com)、供本機開發使用的
http://localhost:3000,以及原生自訂 scheme(myapp://connected)。其他任何值——localhost
以外的純 http:// 來源,或根本不是來源的東西——在此端點建立的連結上會被忽略:連結仍然有效,
只是不會送出任何事件。它是選填的,因此省略它也不是錯誤。三者之中,只有前兩者會收到事件。自訂 scheme 是行動應用程式的返回目標,無法接收事件,
因為沒有可以接收訊息的瀏覽器視窗;原生應用程式改為輪詢
取得 Link Session。請參閱連結完成事件。**在 connect 模式中 origin 是必填的,且會被檢查。**上述的寬鬆處理是 grid 模式的行為。
帶 mode: "connect" 時,省略它會回傳 code: 505,而不屬於三種可接受形態的值會回傳
code: 506,其 details 會重複你送出的形態。string
選填。你的連結網域,適用於你的帳戶擁有多個網域時。省略時會使用你帳戶本身的網域。未註冊到你帳戶的網域
會被拒絕。
object
寄送內含此連結的 Connect Accounts 電子郵件,讓你的使用者可以直接前往他們的連結頁面。需要提供
to
地址。需要 Max Pack。回應會在 emailSent 中報告寄送結果,寄送失敗會回傳 code: 333 而非成功回應。請參閱 Connect Accounts 電子郵件。Connect 模式
mode: "connect" 建立的是供你自行代管的連結介面使用的工作階段,而不是供代管連結頁面使用的。
你會取得兩種 connect 形態中的哪一種,取決於一件事——你是否傳入 network:
| 你送出 | 你取回 | 你要做的事 |
|---|---|---|
mode: "connect" 加上一個 network | 指向單一網路連結頁面的 url | 在彈出視窗中開啟它——這就是直接模式 |
mode: "connect" 且沒有 network | 一個 token,完全沒有 URL | 交給你自己的前端 |
**回應中的機密恰好出現一次。**一個回應要嘛有
url,要嘛有 token,絕不會兩者都有,也絕不會
有兩個 URL。直接模式工作階段的 token 就在 url 裡,與 grid 模式相同;沒有 URL 可承載 token 的
工作階段則改為回傳裸 token。其餘部分在三種模式中都相同:sessionId、expiresAt、
emailSent,以及當 User Profile 有標題時的 title。Connect 模式的需求
這兩項都不是獨立的 body 欄位——第一項是帳戶權限,第二項是上方的origin
參數,connect 模式將它變為必填。
**Max Pack。**沒有它,呼叫會回傳 code: 504,且在檢查 connect 模式參數
之前就會檢查,因此修正 origin 或 network 不會改變這個結果。如果你需要在沒有 Max Pack 的
帳戶上啟用 connect 模式,請聯絡支援團隊。
**每個工作階段都要有 origin。**沒有允許清單,也沒有註冊步驟——你在每次呼叫時送出它,它會被
儲存在工作階段上,因此新的環境不需要我們這一側的任何設定。接受三種形態:
https來源——https://app.example.com- 原生自訂 scheme——
myapp://connected - 供本機開發使用的
http://localhost或http://localhost:3000
code: 505,
不屬於三種形態的任何值會回傳 code: 506。
email 不能用於沒有 network 的工作階段,因為沒有可以放進電子郵件的連結——該形態回傳的是
供你自己前端使用的 token。此呼叫會回傳 code: 510。請加入 network 建立有 URL 的直接模式
工作階段,或省略 email。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
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);
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
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);
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}");
}
}
}
}
{
"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.
}
{
"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"
}
{
"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"
}
{
"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"
}
{
"action": "JWT",
"status": "error",
"code": 188,
"message": "Missing or incorrect privateKey, profileKey, domain, email 'to', or expiresIn fields."
}
{
"action": "JWT",
"status": "error",
"code": 189,
"message": "Error generating JWT. Check the sent parameters.",
"details": "Missing or incorrect domain."
}
{
"action": "JWT",
"status": "error",
"code": 340,
"message": "Max Pack required. Go to your dashboard to add the Max Pack."
}