List Messages
curl --request GET \
--url https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messagesimport requests
url = "https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages', 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/accounts/{id}/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages")
.asString();require 'uri'
require 'net/http'
url = URI("https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyLinkedIn
List Messages
Synced LinkedIn messages for a connected account, newest first.
GET
/
v1
/
tools
/
linkedin
/
accounts
/
{id}
/
messages
List Messages
curl --request GET \
--url https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messagesimport requests
url = "https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages', 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/accounts/{id}/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages")
.asString();require 'uri'
require 'net/http'
url = URI("https://win.oneshotagent.com/v1/tools/linkedin/accounts/{id}/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyReturns the account’s synced messages, newest first, filterable by conversation, direction, and time. Free, proof-signed, keyset-paginated on
(sent_at, id) so a growing inbox never shifts a page.
Query
string
Restrict to one conversation.
string
inbound (the human received it) or outbound (the human, or an agent through this account, sent it).string
ISO time. Returns only messages sent after it.
direction=inbound + since is the reply watermark for a cadence engine.string
ISO time. Returns only messages edited, read or deleted after it.
string
next_cursor from the previous page.number
default:"50"
1–100.
boolean
default:"false"
Include messages deleted upstream (kept with
deleted: true).Response
{
"messages": [
{
"id": "…",
"conversation_id": "…",
"provider_message_id": "…",
"direction": "inbound",
"sender_provider_id": "…",
"sender_name": "Sam Rivera",
"text": "Happy to chat next week — Tuesday?",
"sent_at": "2026-09-15T11:58:00.000Z",
"seen": false,
"edited": false,
"deleted": false,
"attachments": [ { "id": "…", "type": "img", "mimetype": "image/png", "size": 48211, "file_name": null } ],
"source": "webhook",
"ingested_at": "2026-09-15T11:58:04.000Z",
"updated_at": "2026-09-15T11:58:04.000Z"
}
],
"next_cursor": null,
"has_more": false,
"coverage": { "…": "…" },
"sync_state": "complete"
}
sourcesays who first stored the row:sync(a history run),webhook(real-time), orsend(a reply through this account).- Attachments are metadata only. Download URLs are never stored, so they cannot leak. Downloading is not available in v1.
- Edits keep only the latest text plus an
editedflag. There is no edit history upstream.
Stop-on-reply pattern
Walk the whole window before you move the watermark.// Walk every page before moving the watermark: results are newest-first,
// so advancing it after page one would skip anything on later pages.
let cursor: string | undefined;
let newest: string | undefined;
do {
const page = await agent.linkedinMessages({ accountId, direction: 'inbound', since: watermark, limit: 100, cursor });
for (const m of page.messages) {
// m.conversation_id → your prospect; stop the cadence, record the reply
if (!newest || m.sent_at > newest) newest = m.sent_at;
}
cursor = page.has_more ? page.next_cursor! : undefined;
} while (cursor);
if (newest) watermark = newest; // only after the whole window was processed