Connect a LinkedIn Account
curl --request POST \
--url https://win.oneshotagent.com/v1/tools/linkedin/connect \
--header 'Content-Type: application/json' \
--data '
{
"requested_actions": [
"<string>"
],
"success_redirect_url": "<string>",
"failure_redirect_url": "<string>"
}
'import requests
url = "https://win.oneshotagent.com/v1/tools/linkedin/connect"
payload = {
"requested_actions": ["<string>"],
"success_redirect_url": "<string>",
"failure_redirect_url": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
requested_actions: ['<string>'],
success_redirect_url: '<string>',
failure_redirect_url: '<string>'
})
};
fetch('https://win.oneshotagent.com/v1/tools/linkedin/connect', 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://win.oneshotagent.com/v1/tools/linkedin/connect",
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([
'requested_actions' => [
'<string>'
],
'success_redirect_url' => '<string>',
'failure_redirect_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$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://win.oneshotagent.com/v1/tools/linkedin/connect"
payload := strings.NewReader("{\n \"requested_actions\": [\n \"<string>\"\n ],\n \"success_redirect_url\": \"<string>\",\n \"failure_redirect_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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://win.oneshotagent.com/v1/tools/linkedin/connect")
.header("Content-Type", "application/json")
.body("{\n \"requested_actions\": [\n \"<string>\"\n ],\n \"success_redirect_url\": \"<string>\",\n \"failure_redirect_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://win.oneshotagent.com/v1/tools/linkedin/connect")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"requested_actions\": [\n \"<string>\"\n ],\n \"success_redirect_url\": \"<string>\",\n \"failure_redirect_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyLinkedIn
Connect a LinkedIn Account
Create a hosted LinkedIn login link for a human to connect their own account and grant the agent specific actions.
POST
/
v1
/
tools
/
linkedin
/
connect
Connect a LinkedIn Account
curl --request POST \
--url https://win.oneshotagent.com/v1/tools/linkedin/connect \
--header 'Content-Type: application/json' \
--data '
{
"requested_actions": [
"<string>"
],
"success_redirect_url": "<string>",
"failure_redirect_url": "<string>"
}
'import requests
url = "https://win.oneshotagent.com/v1/tools/linkedin/connect"
payload = {
"requested_actions": ["<string>"],
"success_redirect_url": "<string>",
"failure_redirect_url": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
requested_actions: ['<string>'],
success_redirect_url: '<string>',
failure_redirect_url: '<string>'
})
};
fetch('https://win.oneshotagent.com/v1/tools/linkedin/connect', 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://win.oneshotagent.com/v1/tools/linkedin/connect",
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([
'requested_actions' => [
'<string>'
],
'success_redirect_url' => '<string>',
'failure_redirect_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$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://win.oneshotagent.com/v1/tools/linkedin/connect"
payload := strings.NewReader("{\n \"requested_actions\": [\n \"<string>\"\n ],\n \"success_redirect_url\": \"<string>\",\n \"failure_redirect_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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://win.oneshotagent.com/v1/tools/linkedin/connect")
.header("Content-Type", "application/json")
.body("{\n \"requested_actions\": [\n \"<string>\"\n ],\n \"success_redirect_url\": \"<string>\",\n \"failure_redirect_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://win.oneshotagent.com/v1/tools/linkedin/connect")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"requested_actions\": [\n \"<string>\"\n ],\n \"success_redirect_url\": \"<string>\",\n \"failure_redirect_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyCreates an expiring connection intent and returns a hosted LinkedIn login URL. Free. Authenticated with the signed agent proof (
An agent can have at most 3 connection links open (pending, unexpired) at a time. A fourth returns
x-agent-proof), which the SDKs sign for you.
The human opens the URL and signs in (password, SSO, 2FA, whatever their account needs). OneShot is notified when the login completes. Ownership is bound to your agent only after OneShot verifies the account server-side. The redirect the human sees proves nothing on its own.
The
url is returned exactly once and is never stored or logged. Hand it to the human directly. It expires in 30 minutes. Open it top-level, because the hosted page cannot solve LinkedIn’s captcha inside an iframe.Request
string[]
required
The actions you are asking the human to grant: any of
read, reply, view_profile, react, invite (comment is reserved). Ask only for what the agent needs. The human sees this list as the scope of what they are delegating.string
https:// URL the human is sent to after connecting. No embedded credentials.string
https:// URL on failure.409 intent_pending.
Response
{
"intent_id": "8f0c…",
"type": "create",
"url": "https://account.unipile.com/…",
"expires_at": "2026-09-15T12:30:00.000Z",
"status": "pending",
"requested_actions": ["read", "reply"]
}
Poll the intent
GET /v1/tools/linkedin/connect/{intent_id} (free, proof-signed) returns the intent with status ∈ pending · verifying · completed · failed · expired · cancelled. completed carries the connected account. failed carries a failure_reason:
failure_reason | Meaning |
|---|---|
callback_mismatch | The provider’s notification did not match this intent. Nothing was bound. |
wrong_provider_type | The connected account is not a LinkedIn account. |
source_not_ok | LinkedIn reported the session as not usable right after login. Try again. |
identity_mismatch | On reconnect: a different LinkedIn identity signed in. |
duplicate_member | This human is already connected to this agent (the duplicate upstream connection was deleted). |
account_not_found / verify_exhausted | The account could not be read back from the provider. |
Reconnect
Reconnect keeps the account and its history while the human re-authenticates.POST /v1/tools/linkedin/accounts/{id}/reconnect issues a hosted link for an existing account, to restore an expired session or to add granted actions while it is still connected. The intent type is reconnect.
The human must complete fresh hosted authentication as the same LinkedIn identity. Creating the link or following the browser redirect does not change permissions. Poll the intent until completed confirms server-side verification.
requested_actions is the complete desired grant, not just the actions to add. Include existing actions you want to keep. Omit the field to keep the current grant. Changing the set increments grant_version and refreshes the grant timestamp. An unchanged set keeps its version.
The account ID, messages, conversations, coverage, and sync progress stay intact, with no new history enumeration. Adding actions preserves queued writes. Removing any action invalidates older queued writes, even if it is added back later. Revoked or deleted upstream accounts still require a new connection.
For an account whose complete current grant is read, reply, and view_profile (and no other actions), add invite like this:
const intent = await agent.reconnectLinkedInAccount(account.id, {
requestedActions: ['read', 'reply', 'view_profile', 'invite'],
});
// Show intent.url to the human, then poll getLinkedInConnection(intent.intent_id).
intent = client.reconnect_linkedin_account(
account["id"], requested_actions=list(dict.fromkeys([*account["allowed_actions"], "invite"]))
)
# Async: await client.areconnect_linkedin_account(...).
# Show intent["url"] to the human, then poll get_linkedin_connection(intent["intent_id"]).
Example
const intent = await agent.linkedinConnect({ requestedActions: ['read', 'reply'] });
// show intent.url to the human …
let status = await agent.getLinkedInConnection(intent.intent_id);
while (status.status === 'pending' || status.status === 'verifying') {
await new Promise((r) => setTimeout(r, 5_000));
status = await agent.getLinkedInConnection(intent.intent_id);
}
if (status.status === 'completed') console.log(status.account!.id, status.account!.allowed_actions);
intent = client.linkedin_connect(["read", "reply"])
# show intent["url"] to the human …
status = client.get_linkedin_connection(intent["intent_id"])
Errors
| Status | error | Meaning |
|---|---|---|
| 400 | invalid_request | Unknown action, non-https redirect, or empty list. |
| 409 | intent_pending | Three links are already open. Wait for one to complete or expire. |
| 502 | linkedin_link_unavailable | The connection provider could not issue a link. Retry shortly. |