List inbox conversations
https://myagentmail.com/linkedin/conversationsReturns the most recent ~20 conversations on the connected account.
Response shape — read this before parsing
The response returns two parallel views of the people in each thread:
participants[]— preferred. Already enriched withname,slug, andheadlineextracted from the LinkedIn payload server- side, with zero extra API calls. Use these for rendering.participantUrns[]— back-compat, URN strings only.
There is no participant.name at the top level, no peer, no
otherPerson, no lastMessage.snippet, no last_message field. If
you normalise against those, every contact renders as "(unnamed)".
Field map (exact names, camelCase):
conversationUrn—urn:li:msg_conversation:(...). Pass this toGET /linkedin/conversations/{conversationUrn}/messages. Always URL-encode when used as a path parameter.participants[]— Enriched:{ urn, name, slug, headline }. Any of name/slug/headline may benull(deleted accounts, restricted profiles), buturnis always present.participantUrns[]— Mirror ofparticipants[].urn. Kept for back-compat with clients written before the enrichment landed.title— Group chat title only. Null on 1-on-1 conversations. Don't fall back to this for the contact name; useparticipantsinstead.lastMessage.text— Plain text body. Notsnippet, notpreview, notbodyText.lastMessage.senderName— Display name of the sender of the latest message. Already resolved server-side; null only when LinkedIn omits the inline profile.lastMessage.senderUrn— URN of the same sender.lastActivityAt,lastReadAt,lastMessage.deliveredAt— Unix ms, not seconds. Nullable for system-initiated threads.
Worked example response
{
"ok": true,
"conversations": [
{
"conversationUrn": "urn:li:msg_conversation:(urn:li:fsd_profile:ACoAAA…,2-MWE…)",
"backendUrn": "urn:li:fs_conversation:2-MWE…",
"isGroup": false,
"title": null,
"lastActivityAt": 1715990400000,
"lastReadAt": 1715990405000,
"unreadCount": 1,
"read": false,
"participants": [
{
"urn": "urn:li:fsd_profile:ACoAAA…aaaa",
"name": "Jane Doe",
"slug": "jane-doe-1a2b3c",
"headline": "Head of Sales at Acme"
},
{
"urn": "urn:li:fsd_profile:ACoAAA…me",
"name": "Me",
"slug": "me-1a2b3c",
"headline": null
}
],
"participantUrns": [
"urn:li:fsd_profile:ACoAAA…aaaa",
"urn:li:fsd_profile:ACoAAA…me"
],
"lastMessage": {
"messageUrn": "urn:li:msg_message:(urn:li:fsd_profile:ACoAAA…,2-MWE…)",
"text": "Sure, happy to chat — Tuesday at 2pm work?",
"senderUrn": "urn:li:fsd_profile:ACoAAA…aaaa",
"senderName": "Jane Doe",
"deliveredAt": 1715990400000
}
}
]
}
Rendering the contact name (1-on-1 thread)
Filter your own viewer URN out of participants, then read name
directly. No profile-lookup round-trip needed:
const { conversations } = await client.linkedinListConversations({ sessionId });
const viewerUrn = (await client.linkedinGetSession({ id: sessionId })).viewerProfileUrn;
for (const c of conversations) {
const other = c.participants.find(p => p.urn !== viewerUrn);
const displayName = other?.name
?? (c.isGroup && c.title)
?? "(unknown)";
// …render
}
For group chats, prefer title; if absent (rare), join the other
participants' names with commas. For the rare case where
participants[i].name is null (deleted / restricted), fall back to
POST /linkedin/profile/lookup with the URN — but you'll only need
that on a handful of edge cases, not every conversation.
Query parameters
sessionIdrequired string |
Responses
okboolean | |
conversationsobject[] | |
conversationUrnstring | `urn:li:msg_conversation:(…)`. URL-encode when used as a path parameter. |
backendUrnstring | Internal backend ref. Not usable as a path param. |
isGroupboolean | True for 3+ participants. |
titlestring | Group chat title. **Null on 1-on-1 conversations** — don't display as the contact name. |
lastActivityAtinteger | Unix **ms** (not seconds). Time of the most recent message or system event. |
lastReadAtinteger | Unix ms when the viewer last read this thread. |
unreadCountinteger | Messages the viewer hasn't read yet. |
readboolean | |
participantsobject[] | Enriched participant list — extracted server-side from the same Voyager payload, so no extra API calls or `profile_lookup` budget is spent. Includes the viewer themselves; filter them out by comparing each URN against the viewer URN (available via GET /linkedin/sessions/{id}). For the rare null `name` (deleted / restricted accounts), fall back to POST /linkedin/profile/lookup with the URN. |
urnstring | `urn:li:fsd_profile:xxxx`. |
namestring | Display name, typically `"First Last"`. Null when LinkedIn omits the inline profile. |
slugstring | `linkedin.com/in/<slug>` segment when LinkedIn includes `publicIdentifier` inline; otherwise the trailing URN token as a fallback (opaque but stable for keying). |
headlinestring | One-line title shown next to the participant on LinkedIn. |
participantUrnsstring[] | URN-only list, mirror of `participants[].urn`. Retained for back-compat with clients written before the enrichment landed — prefer `participants` for new code. |
lastMessageobject | Null when LinkedIn has no rendered preview (rare — system threads). |
messageUrnstring | |
textstring | Plain text. Not `snippet` / `preview` / `bodyText`. |
senderUrnstring | URN of the sender. |
senderNamestring | Display name of the sender of the latest message, resolved server-side from the same Voyager payload. Null when LinkedIn omits the inline profile (rare). |
deliveredAtinteger | Unix ms. |
Authentication
Send your API key in the X-API-Key header (or Authorization: Bearer <key>). Any prefix accepted by this endpoint — tk_, wk_, ak_, or sa_ — is documented in the key prefix table.