curl --request POST \
--url https://social.linkiasoft.com/api/v1/connect-sessions \
--header 'Content-Type: application/json' \
--header 'X-Tenant-Id: <api-key>' \
--header 'x-api-key: <api-key>' \
--data '
{
"platform": "whatsapp",
"origin": "https://app.example.com",
"state": "user-4821"
}
'import requests
url = "https://social.linkiasoft.com/api/v1/connect-sessions"
payload = {
"platform": "whatsapp",
"origin": "https://app.example.com",
"state": "user-4821"
}
headers = {
"x-api-key": "<api-key>",
"X-Tenant-Id": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-api-key': '<api-key>',
'X-Tenant-Id': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({platform: 'whatsapp', origin: 'https://app.example.com', state: 'user-4821'})
};
fetch('https://social.linkiasoft.com/api/v1/connect-sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://social.linkiasoft.com/api/v1/connect-sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'platform' => 'whatsapp',
'origin' => 'https://app.example.com',
'state' => 'user-4821'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Tenant-Id: <api-key>",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://social.linkiasoft.com/api/v1/connect-sessions"
payload := strings.NewReader("{\n \"platform\": \"whatsapp\",\n \"origin\": \"https://app.example.com\",\n \"state\": \"user-4821\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("X-Tenant-Id", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://social.linkiasoft.com/api/v1/connect-sessions")
.header("x-api-key", "<api-key>")
.header("X-Tenant-Id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"platform\": \"whatsapp\",\n \"origin\": \"https://app.example.com\",\n \"state\": \"user-4821\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://social.linkiasoft.com/api/v1/connect-sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["X-Tenant-Id"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"platform\": \"whatsapp\",\n \"origin\": \"https://app.example.com\",\n \"state\": \"user-4821\"\n}"
response = http.request(request)
puts response.read_body{
"connectUrl": "https://crm.linkiasoft.com/connect#token=cst_...",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"platform": "whatsapp",
"status": "pending",
"channelId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"channelName": "<string>",
"state": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"expiresAt": "2023-11-07T05:31:56Z",
"completedAt": "2023-11-07T05:31:56Z"
}{
"statusCode": 403,
"message": "API key missing required scope(s): conversations:read",
"error": "Forbidden"
}{
"statusCode": 403,
"message": "API key missing required scope(s): conversations:read",
"error": "Forbidden"
}{
"statusCode": 403,
"message": "API key missing required scope(s): conversations:read",
"error": "Forbidden"
}Create a connect link
Returns a one-time connectUrl to open in a popup from your frontend. The popup runs
the provider sign-in and reports the result back to your window (at origin) or to
your redirectUri. The channel is created in the workspace that owns the API key.
The link works once and expires after 30 minutes. Create a new session for every attempt, and never log the URL — it is a credential.
Requires channels:manage.
curl --request POST \
--url https://social.linkiasoft.com/api/v1/connect-sessions \
--header 'Content-Type: application/json' \
--header 'X-Tenant-Id: <api-key>' \
--header 'x-api-key: <api-key>' \
--data '
{
"platform": "whatsapp",
"origin": "https://app.example.com",
"state": "user-4821"
}
'import requests
url = "https://social.linkiasoft.com/api/v1/connect-sessions"
payload = {
"platform": "whatsapp",
"origin": "https://app.example.com",
"state": "user-4821"
}
headers = {
"x-api-key": "<api-key>",
"X-Tenant-Id": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-api-key': '<api-key>',
'X-Tenant-Id': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({platform: 'whatsapp', origin: 'https://app.example.com', state: 'user-4821'})
};
fetch('https://social.linkiasoft.com/api/v1/connect-sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://social.linkiasoft.com/api/v1/connect-sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'platform' => 'whatsapp',
'origin' => 'https://app.example.com',
'state' => 'user-4821'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Tenant-Id: <api-key>",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://social.linkiasoft.com/api/v1/connect-sessions"
payload := strings.NewReader("{\n \"platform\": \"whatsapp\",\n \"origin\": \"https://app.example.com\",\n \"state\": \"user-4821\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("X-Tenant-Id", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://social.linkiasoft.com/api/v1/connect-sessions")
.header("x-api-key", "<api-key>")
.header("X-Tenant-Id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"platform\": \"whatsapp\",\n \"origin\": \"https://app.example.com\",\n \"state\": \"user-4821\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://social.linkiasoft.com/api/v1/connect-sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["X-Tenant-Id"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"platform\": \"whatsapp\",\n \"origin\": \"https://app.example.com\",\n \"state\": \"user-4821\"\n}"
response = http.request(request)
puts response.read_body{
"connectUrl": "https://crm.linkiasoft.com/connect#token=cst_...",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"platform": "whatsapp",
"status": "pending",
"channelId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"channelName": "<string>",
"state": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"expiresAt": "2023-11-07T05:31:56Z",
"completedAt": "2023-11-07T05:31:56Z"
}{
"statusCode": 403,
"message": "API key missing required scope(s): conversations:read",
"error": "Forbidden"
}{
"statusCode": 403,
"message": "API key missing required scope(s): conversations:read",
"error": "Forbidden"
}{
"statusCode": 403,
"message": "API key missing required scope(s): conversations:read",
"error": "Forbidden"
}Authorizations
Your workspace API key. Create one in Settings → API Keys; the plaintext value is shown once and never again.
Keys are scoped. A key needs conversations:send to send, conversations:read to
read threads and messages, templates:read to list templates, channels:read
to list channels, and channels:manage to create connect sessions. A key missing
the scope for an endpoint gets 403.
The CRM endpoints use the same resource:action form: leads:read, leads:create,
leads:update, leads:delete, customers:read, customers:create,
customers:update, customers:delete, customers:manage.
Several resources have no scope of their own and borrow one:
| Resource | Governed by |
|---|---|
| Contacts | customers:* |
| Activities | customers:* for customer activities, leads:* for lead activities |
| Tags | customers:read to list, customers:manage to change |
| Pipeline stages | leads:* |
| Quick replies | quick-replies:read / quick-replies:write |
| WhatsApp groups | wa-groups:manage |
Grant only what the integration needs — a key that only sends notifications should
hold conversations:send and nothing else.
Your workspace UUID. Required on every request in addition to x-api-key.
It does not select the workspace — data access is always scoped to the workspace that owns the API key, and a mismatched value cannot read anyone else's data.
Body
Which channel the popup connects. facebook is Messenger. whatsapp_qr links a
number as a WhatsApp Web linked device, by QR scan or pairing code.
whatsapp, whatsapp_qr, facebook, instagram, tiktok whatsapp_qr only: the channel's display name. Defaults to the linked number,
e.g. +201001234567.
100Origin of the window that opens the popup, e.g. https://app.example.com. The
result is sent with postMessage to window.opener at exactly this origin.
Where the popup goes when there is no opener window to notify. Receives
?sessionId=…&status=…&channelId=…&state=….
Your own reference, echoed back in every result. Never interpreted.
512Language of the hosted page.
en, ar Response
The session, with the link to open.
Open this in a popup. The token is in the fragment, so it never reaches a server log.
"https://crm.linkiasoft.com/connect#token=cst_..."
whatsapp, whatsapp_qr, facebook, instagram, tiktok expired means the 30-minute link ran out before the person finished.
pending, connected, cancelled, expired Set once status is connected. Use it as channelId elsewhere in this API.
The state you sent, unchanged.
When the link stops working.

