# Unipile

> Send and read LinkedIn, WhatsApp, Instagram and Telegram messages, run LinkedIn outreach and search, publish posts, and manage email and calendars, all through one Unipile connection.

App · Messaging · 90 actions. Web page: https://docs.lodol.com/docs/integrations/unipile

## Actions

### Cancel a calendar event

Cancel an event, keeping it on the calendar as cancelled and telling the guests.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- Event (`event_id`, text, required): The event's id, from 'List calendar events'.
- Message (`comment`, text): A note to include with the cancellation.

**Outputs**

- `cancelled` (true/false): True after a cancel, false after a restore.
- `event_id` (text): The event acted on.

**Example output**

```json
{
  "cancelled": true,
  "event_id": "ev_5Tg"
}
```

### Comment on a post

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Add a comment to a post. 'Comment as' comments from a company page you administer. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`text`, text, required): What to say.
- Comment as company (`comment_as`, text): A company page id to comment as, instead of your own profile.
- Attachments (`attachments`, list): Files to send, up to 15 MB each. Upload them here, or reference a document produced by an earlier step.

**Outputs**

- `author` (object): Who wrote it.
- `created_at` (text): When it was posted.
- `id` (text): The comment id.
- `reactions_counter` (number): Reactions on the comment.
- `reply_counter` (number): Replies to the comment.
- `text` (text): The comment text.

**Example output**

```json
{
  "id": "cmt_2Bq",
  "text": "Congratulations!"
}
```

### Create a calendar

Create a new calendar on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Name (`name`, text, required): What to call the calendar.
- Description (`description`, text): What the calendar is for.
- Timezone (`timezone`, text): IANA timezone, e.g. Europe/London.

**Outputs**

- `description` (text): Calendar description.
- `id` (text): The calendar id.
- `is_default` (true/false): Whether this is the account's default calendar.
- `is_owned_by_user` (true/false): Whether the account owns it, rather than subscribing.
- `is_read_only` (true/false): True when events cannot be written here.
- `name` (text): Calendar name.
- `timezone` (text): The calendar's IANA timezone.

**Example output**

```json
{
  "id": "cal_2Lm",
  "name": "Interviews"
}
```

### Create a calendar event

Google and Microsoft calendars only. Create an event, optionally inviting people and adding a video-conference link.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- Title (`title`, text, required): What the event is called.
- Start (`start`, date and time, required): When it starts. A date and time makes a normal event; a date on its own (2026-09-22) makes an all-day one.
- End (`end`, date and time, required): When it ends. Match the shape of the start: a date and time, or a date for an all-day event.
- Description (`body`, text): The event's description.
- Location (`location`, text): Where it takes place.
- Guests (`attendees`, list): Email addresses to invite.
- Timezone (`timezone`, text): IANA timezone for the times above.
- Visibility (`visibility`, text): Whether the event is public or private. One of: `public`, `private`.
- Shows as (`transparency`, text): Whether the time shows as busy or free. One of: `opaque` (Busy), `transparent` (Free).
- Notify guests (`notify`, text): Who gets an invitation email. One of: `all` (Notify everyone), `externalOnly` (Notify external guests only), `none` (Notify no one).
- Add video link (`add_conference`, true/false): Create a Meet or Teams link for the event.

**Outputs**

- `attendees` (list): Invitees and their responses.
- `body` (text): Event description.
- `end` (text): End, ISO 8601.
- `id` (text): The event id.
- `is_cancelled` (true/false): Whether it has been cancelled.
- `location` (text): Where it takes place.
- `start` (text): Start, ISO 8601.
- `title` (text): Event title.

**Example output**

```json
{
  "end": "2026-09-23T11:00:00.000Z",
  "id": "ev_5Tg",
  "start": "2026-09-23T10:00:00.000Z",
  "title": "Design review"
}
```

### Create a draft

Works with any mailbox: Gmail, Outlook or IMAP. Save an email as a draft without sending it. Useful for a human-in-the-loop flow: the workflow writes the email, a person reviews it in their mailbox and sends it.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- To (`to`, list, required): Recipient addresses.
- Subject (`subject`, text): Subject line.
- Body (`body`, text): Plain-text body.
- HTML body (`html`, text): HTML body.
- Cc (`cc`, list): Cc addresses.
- Bcc (`bcc`, list): Bcc addresses.
- Attachments (`attachments`, list): Files to send, up to 15 MB each. Upload them here, or reference a document produced by an earlier step.

**Outputs**

- `body` (text): The draft body.
- `id` (text): The draft id.
- `subject` (text): Subject line.
- `to` (list): To recipients.

**Example output**

```json
{
  "id": "dr_6Vb",
  "subject": "Draft reply"
}
```

### Create a mail folder

Create a folder in the mailbox.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Name (`name`, text, required): What to call the folder.

**Outputs**

- `id` (text): The folder id.
- `is_system` (true/false): True for built-in folders like Inbox and Sent.
- `name` (text): Folder name as shown in the mailbox.
- `total_count` (number): Emails in the folder.
- `unread_count` (number): Unread emails in the folder.

**Example output**

```json
{
  "id": "Label_42",
  "is_system": false,
  "name": "Invoices"
}
```

### Delete a calendar

Delete a calendar and every event in it. This cannot be undone.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.

**Outputs**

- `deleted` (true/false): True when the delete succeeded.
- `id` (text): The id of what was deleted.

**Example output**

```json
{
  "deleted": true,
  "id": "cal_2Lm"
}
```

### Delete a calendar event

Google and Microsoft calendars only. Delete an event outright. Use 'Cancel a calendar event' instead if the guests should be told and the event should stay visible as cancelled.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- Event (`event_id`, text, required): The event's id, from 'List calendar events'.

**Outputs**

- `deleted` (true/false): True when the delete succeeded.
- `id` (text): The id of what was deleted.

**Example output**

```json
{
  "deleted": true,
  "id": "ev_5Tg"
}
```

### Delete a comment

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Delete a comment you wrote. This cannot be undone.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`comment_id`, text, required): The comment's id, from 'List post comments'.

**Outputs**

- `deleted` (true/false): True when the delete succeeded.
- `id` (text): The id of what was deleted.

**Example output**

```json
{
  "deleted": true,
  "id": "cmt_2Bq"
}
```

### Delete a draft

Works with any mailbox: Gmail, Outlook or IMAP. Delete a saved draft.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Draft (`draft_id`, text, required): The draft's id, from 'List drafts'.

**Outputs**

- `deleted` (true/false): True when the delete succeeded.
- `id` (text): The id of what was deleted.

**Example output**

```json
{
  "deleted": true,
  "id": "dr_6Vb"
}
```

### Delete a mail folder

Works with any mailbox: Gmail, Outlook or IMAP. Delete a folder. The emails inside it are not deleted; they stay in the mailbox.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Folder (`folder_id`, text, required): Which mail folder. Pick it from the list, or paste an id.

**Outputs**

- `deleted` (true/false): True when the delete succeeded.
- `id` (text): The id of what was deleted.

**Example output**

```json
{
  "deleted": true,
  "id": "Label_42"
}
```

### Delete a message

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Delete a message you sent. Supported on WhatsApp and LinkedIn only, and on LinkedIn only within 60 minutes of sending.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.

**Outputs**

- `deleted` (true/false): True when the delete succeeded.
- `id` (text): The id of what was deleted.

**Example output**

```json
{
  "deleted": true,
  "id": "msg_1aZ"
}
```

### Delete a post

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Delete a post you published. This cannot be undone.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.

**Outputs**

- `deleted` (true/false): True when the delete succeeded.
- `id` (text): The id of what was deleted.

**Example output**

```json
{
  "deleted": true,
  "id": "post_7Kd"
}
```

### Download an email attachment

Works with any mailbox: Gmail, Outlook or IMAP. Download a file attached to an email. Comes back base64-encoded so it can feed another step's file input.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Email (`email_id`, text, required): The email's id, from 'List emails'.
- Attachment (`attachment_id`, text, required): The attachment's id, from the email's 'attachments' list.

**Outputs**

- `content` (text): The file's bytes, base64-encoded so it can be passed to another step's file input.
- `id` (text): The attachment id.
- `mimetype` (text): Media type reported by the provider.
- `size` (number): Size in bytes.

**Example output**

```json
{
  "content": "JVBERi0xLjQK\u2026",
  "id": "att_1Qw",
  "mimetype": "application/pdf",
  "size": 90210
}
```

### Edit a comment

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Edit a comment you wrote.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`comment_id`, text, required): The comment's id, from 'List post comments'.
- New text (`text`, text, required): What the comment should say instead.

**Outputs**

- `author` (object): Who wrote it.
- `created_at` (text): When it was posted.
- `id` (text): The comment id.
- `reactions_counter` (number): Reactions on the comment.
- `reply_counter` (number): Replies to the comment.
- `text` (text): The comment text.

**Example output**

```json
{
  "id": "cmt_2Bq",
  "text": "Congratulations, both of you!"
}
```

### Edit a message

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Edit a message you sent. Providers put a short window on this (WhatsApp around 15 minutes, LinkedIn Classic 60), after which the edit is refused.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.
- New text (`text`, text, required): What the message should say instead.

**Outputs**

- `attachments` (list): Files carried by the message.
- `chat_id` (text): The chat it belongs to.
- `id` (text): The message id.
- `is_seen` (true/false): Whether the other participants have read it.
- `is_sender` (true/false): True when the linked account sent it.
- `sender_id` (text): Provider id of whoever sent it.
- `text` (text): The message body as plain text.
- `timestamp` (text): When it was sent, ISO 8601.

**Example output**

```json
{
  "id": "msg_1aZ",
  "text": "Thanks \u2014 Tuesday works better."
}
```

### Edit a post

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Edit a post you published.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- New text (`text`, text, required): What the post should say instead.

**Outputs**

- `author` (object): Who published it.
- `comments_counter` (number): Total comments.
- `created_at` (text): When it was published.
- `id` (text): The post id.
- `reactions_counter` (number): Total reactions. Null when the provider hides the count.
- `reposts_counter` (number): Total reshares.
- `share_url` (text): Link to the post.
- `text` (text): The post's text.

**Example output**

```json
{
  "id": "post_7Kd",
  "text": "We are still hiring."
}
```

### Endorse a skill

Endorse a skill on someone's LinkedIn profile. Identify the skill by its endorsement id rather than its name: run 'Get a profile' on the person with 'Extra sections' set to linkedin_skills first, and chain the id from there. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Person (`member_id`, text, required): Whose skill to endorse. Accepts an id, a handle, or a pasted profile URL.
- Skill (`skill_id`, text, required): The skill's endorsement id, from 'Get a profile' with 'Extra sections' set to linkedin_skills. The skill's name will not work here.

**Outputs**

- `endorsed` (true/false): True when the endorsement went through.
- `member_id` (text): Who was endorsed.
- `skill_id` (text): The endorsed skill's id on that profile.

**Example output**

```json
{
  "endorsed": true,
  "member_id": "ACoAAAcDMMQ",
  "skill_id": "ACoAAAcDMMQ:COBOL"
}
```

### Find the chat with a person

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Find the existing 1:1 conversation with someone, if there is one. More direct than listing chats and filtering, and unlike listing an inbox, it finds the conversation wherever it sits, which matters because an archived chat stops appearing in Classic Primary. Give the provider id; a handle is resolved for you at the cost of one extra profile read.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text, required): Who to act on. Accepts a provider id, a handle, or a pasted profile URL: all three work, so there is no lookup step.

**Outputs**

- `exists` (true/false): False when this person has no conversation yet.
- `has_history` (true/false): Whether the conversation has messages in it.
- `id` (text): The conversation's id, or null when there is none yet.
- `inbox_id` (text): Which inbox it is in — the authoritative answer, which an inbox listing does not always agree with.

**Example output**

```json
{
  "exists": true,
  "has_history": true,
  "id": "chat_8vQ2",
  "inbox_id": "CLASSIC_PRIMARY"
}
```

### Follow a person

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Follow someone without sending a connection request. A lighter touch than an invitation and not subject to the invitation limits, though it still counts as an action on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text, required): Who to act on. Accepts a provider id, a handle, or a pasted profile URL: all three work, so there is no lookup step.

**Outputs**

- `following` (true/false): True after a follow, false after an unfollow.
- `user_id` (text): Who was followed.

**Example output**

```json
{
  "following": true,
  "user_id": "ACoAAAcDMMQ"
}
```

### Forward a message

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Forward a message into another conversation.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.
- Forward to chat (`to_chat_id`, text, required): The id of the conversation to forward it into.

**Outputs**

- `chat_id` (text): The chat it was forwarded into.
- `message_id` (text): The id of the forwarded copy.

**Example output**

```json
{
  "forwarded": true
}
```

### Get a calendar

Retrieve one calendar.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.

**Outputs**

- `description` (text): Calendar description.
- `id` (text): The calendar id.
- `is_default` (true/false): Whether this is the account's default calendar.
- `is_owned_by_user` (true/false): Whether the account owns it, rather than subscribing.
- `is_read_only` (true/false): True when events cannot be written here.
- `name` (text): Calendar name.
- `timezone` (text): The calendar's IANA timezone.

**Example output**

```json
{
  "id": "primary",
  "is_default": true,
  "is_read_only": false,
  "name": "Ada Lovelace"
}
```

### Get a calendar event

Google and Microsoft calendars only. Retrieve one event, including its attendees and their responses.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- Event (`event_id`, text, required): The event's id, from 'List calendar events'.

**Outputs**

- `attendees` (list): Invitees and their responses.
- `body` (text): Event description.
- `end` (text): End, ISO 8601.
- `id` (text): The event id.
- `is_cancelled` (true/false): Whether it has been cancelled.
- `location` (text): Where it takes place.
- `start` (text): Start, ISO 8601.
- `title` (text): Event title.

**Example output**

```json
{
  "id": "ev_5Tg",
  "start": "2026-09-23T10:00:00.000Z",
  "title": "Design review"
}
```

### Get a chat

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Retrieve one conversation, including its participants and unread count.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.

**Outputs**

- `id` (text): The chat id, used by every message action.
- `is_1to1` (true/false): True for a direct conversation.
- `is_archived` (true/false): Whether the owner archived it.
- `is_group` (true/false): True for a group conversation.
- `last_message_timestamp` (text): When the most recent message landed.
- `name` (text): Group name, or the other person's name in a 1:1.
- `participants_count` (number): How many people are in it.
- `provider` (text): Which network the chat is on.
- `type` (text): The chat's kind, as the provider classifies it.
- `unread_count` (number): Unread messages in this chat.

**Example output**

```json
{
  "id": "chat_8vQ2",
  "is_1to1": true,
  "name": "Grace Hopper",
  "participants_count": 2,
  "provider": "linkedin",
  "unread_count": 2
}
```

### Get a draft

Works with any mailbox: Gmail, Outlook or IMAP. Retrieve one saved draft.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Draft (`draft_id`, text, required): The draft's id, from 'List drafts'.

**Outputs**

- `body` (text): The draft body.
- `id` (text): The draft id.
- `subject` (text): Subject line.
- `to` (list): To recipients.

**Example output**

```json
{
  "body": "Thanks \u2014 will confirm.",
  "id": "dr_6Vb",
  "subject": "Draft reply"
}
```

### Get a linked account

Any linked account. Retrieve one linked account and its current connection status. A status of 'disconnected' or 'errored' means its owner must reconnect it in Unipile before any other action will work.

**Inputs**

- Account (`account_id`, text, required): Which linked Unipile account to act as. Accounts are linked in your Unipile dashboard, not here: use the refresh button if one you just connected is missing.

**Outputs**

- `id` (text): Unipile's id for the linked account.
- `name` (text): The account's display name.
- `needs_reconnect` (true/false): True when the owner must reconnect it in Unipile.
- `provider` (text): Which network it is on.
- `status` (text): Connection state.

**Example output**

```json
{
  "id": "acc_01HZX9",
  "name": "Ada Lovelace",
  "needs_reconnect": false,
  "provider": "linkedin",
  "status": "running"
}
```

### Get a mail folder

Works with any mailbox: Gmail, Outlook or IMAP. Retrieve one folder and its counts.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Folder (`folder_id`, text, required): Which mail folder. Pick it from the list, or paste an id.

**Outputs**

- `id` (text): The folder id.
- `is_system` (true/false): True for built-in folders like Inbox and Sent.
- `name` (text): Folder name as shown in the mailbox.
- `total_count` (number): Emails in the folder.
- `unread_count` (number): Unread emails in the folder.

**Example output**

```json
{
  "id": "INBOX",
  "name": "Inbox",
  "total_count": 1284,
  "unread_count": 12
}
```

### Get a message

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Retrieve one message, including its attachments' ids.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.

**Outputs**

- `attachments` (list): Files carried by the message.
- `chat_id` (text): The chat it belongs to.
- `id` (text): The message id.
- `is_seen` (true/false): Whether the other participants have read it.
- `is_sender` (true/false): True when the linked account sent it.
- `sender_id` (text): Provider id of whoever sent it.
- `text` (text): The message body as plain text.
- `timestamp` (text): When it was sent, ISO 8601.

**Example output**

```json
{
  "chat_id": "chat_8vQ2",
  "id": "msg_1aZ",
  "is_sender": false,
  "text": "Thanks \u2014 that works for me.",
  "timestamp": "2026-09-21T16:04:11.000Z"
}
```

### Get a post

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Retrieve one post with its reaction and comment counts. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.

**Outputs**

- `author` (object): Who published it.
- `comments_counter` (number): Total comments.
- `created_at` (text): When it was published.
- `id` (text): The post id.
- `reactions_counter` (number): Total reactions. Null when the provider hides the count.
- `reposts_counter` (number): Total reshares.
- `share_url` (text): Link to the post.
- `text` (text): The post's text.

**Example output**

```json
{
  "comment_counter": 7,
  "id": "post_7Kd",
  "reaction_counter": 42,
  "text": "We are hiring."
}
```

### Get a profile

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Retrieve someone's profile. Use 'me' to read the linked account's own. Anyone else counts as a profile view against the account's daily allowance (Unipile's guidance is about 100 a day on LinkedIn), and on LinkedIn the visit is visible to that person unless their settings say otherwise.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text): Whose data to read. Use 'me' for the linked account's own. Otherwise a provider id, a handle, or a pasted profile URL. Default: `me`.
- Extra sections (`with_sections`, list): Extra profile sections to expand, such as experience or education. Leave empty for the basics.
- Variant (`variant`, text): Provider-specific profile variant, where one applies.

**Outputs**

- `description` (text): Headline or one-line summary.
- `display_name` (text): Full name as the provider renders it.
- `first_name` (text): Given name.
- `followers_count` (number): Follower count.
- `handle` (text): Same as 'public_identifier', lifted for chained steps.
- `id` (text): The person's id on the provider.
- `is_premium` (true/false): Whether they hold a paid plan.
- `is_verified` (true/false): Whether the provider verified them.
- `last_name` (text): Family name.
- `location` (text): Free-text location.
- `profile_url` (text): Link to their profile.
- `provider` (text): Which network this came from.
- `provider_id` (text): Same as 'id', lifted for chained steps.
- `public_identifier` (text): The provider's handle, e.g. 'satyanadella'.
- `public_picture_url` (text): Profile picture URL, when public.
- `relations_count` (number): Connection count.
- `specifics` (object): Provider-specific profile data. On LinkedIn this is where the two fields other actions need live: 'notify_visit_token' for 'Report a profile visit', and 'skills' — whose entries carry the 'endorsement_id' that 'Endorse a skill' takes, an ordinal into this list that means nothing without the read it came from. Ask for skills with the 'linkedin_skills' section.

**Example output**

```json
{
  "description": "Rear Admiral, US Navy (ret.)",
  "display_name": "Grace Hopper",
  "handle": "gracehopper",
  "id": "ACoAAAcDMMQ",
  "provider": "linkedin",
  "provider_id": "ACoAAAcDMMQ",
  "public_identifier": "gracehopper",
  "relations_count": 812
}
```

### Get an email

Works with any mailbox: Gmail, Outlook or IMAP. Retrieve one email, with its body and attachment ids.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Email (`email_id`, text, required): The email's id, from 'List emails'.
- Metadata only (`meta_only`, true/false): Leave the body out.

**Outputs**

- `attachments` (list): Files carried by the email.
- `bcc` (list): Bcc recipients.
- `body` (text): Full body. Absent when the call asked for metadata only.
- `cc` (list): Cc recipients.
- `date` (text): When it was sent, ISO 8601.
- `folders` (list): Folders it sits in.
- `from` (list): Sender.
- `id` (text): Unipile's id for the email.
- `is_unread` (true/false): Whether it is still unread.
- `message_id` (text): The RFC 822 Message-ID header.
- `snippet` (text): Short preview of the body.
- `subject` (text): Subject line.
- `thread_id` (text): Groups the email with its replies.
- `to` (list): To recipients.

**Example output**

```json
{
  "body": "Please find attached.",
  "id": "em_4Rt",
  "is_unread": true,
  "subject": "Invoice 1042"
}
```

### Get an email thread

Works with any mailbox: Gmail, Outlook or IMAP. Retrieve a whole conversation: an email and all its replies.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Thread (`thread_id`, text, required): The thread id, from any email's 'thread_id'.
- Metadata only (`meta_only`, true/false): Leave the bodies out.

**Outputs**

- `emails` (list): The emails in the thread.
- `id` (text): The thread id.

**Example output**

```json
{
  "data": [
    {
      "id": "em_4Rt",
      "subject": "Invoice 1042"
    }
  ]
}
```

### List a person's comments

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List comments a person has written. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text): Whose data to read. Use 'me' for the linked account's own. Otherwise a provider id, a handle, or a pasted profile URL. Default: `me`.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The comments on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many there are.

**Example output**

```json
{
  "items": [
    {
      "id": "cmt_2Bq",
      "text": "Congratulations!"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List a person's posts

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List posts written by a person or a company. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text): Whose data to read. Use 'me' for the linked account's own. Otherwise a provider id, a handle, or a pasted profile URL. Default: `me`.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The posts on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many the provider says exist.

**Example output**

```json
{
  "items": [
    {
      "id": "post_7Kd",
      "reaction_counter": 42,
      "text": "We are hiring."
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List a person's reactions

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List the posts and comments a person has reacted to. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text): Whose data to read. Use 'me' for the linked account's own. Otherwise a provider id, a handle, or a pasted profile URL. Default: `me`.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The reactions on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many reactions there are.

**Example output**

```json
{
  "items": [
    {
      "value": "like"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List calendar events

List events in a calendar within a time window.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- From (`start`, date and time): Start of the window.
- To (`end`, date and time): End of the window.
- Title contains (`title`, text): Only events whose title matches.
- Location contains (`location`, text): Only events at a matching location.
- Cancelled only (`is_cancelled`, true/false): Only cancelled events.
- Expand recurring (`expand_recurring`, true/false): Return each occurrence of a recurring event rather than the series.
- Changed since (`updated_after`, date and time): Only events modified after this moment. Use this to poll for changes.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The events in the window.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many events there are.

**Example output**

```json
{
  "items": [
    {
      "end": "2026-09-23T11:00:00.000Z",
      "id": "ev_5Tg",
      "start": "2026-09-23T10:00:00.000Z",
      "title": "Design review"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List calendars

List the calendars on a connected Google or Microsoft account.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The calendars.
- `total_count` (number): How many calendars there are.

**Example output**

```json
{
  "items": [
    {
      "id": "primary",
      "is_default": true,
      "is_read_only": false,
      "name": "Ada Lovelace",
      "timezone": "Europe/London"
    }
  ],
  "total_count": 1
}
```

### List chat messages

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List the messages in a conversation, newest first. Served from Unipile rather than the provider, so this is cheap to call.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- From person (`person_id`, text): Only messages from this person. Accepts an id, a handle or a profile URL.
- Sent after (`after`, date and time): Only messages sent after this moment. Use this to poll for new messages.
- Sent before (`before`, date and time): Only messages sent before this moment.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `has_more` (true/false): Whether another page exists.
- `items` (list): The messages on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many the provider says exist.

**Example output**

```json
{
  "has_more": false,
  "items": [
    {
      "attachments": [],
      "chat_id": "chat_8vQ2",
      "id": "msg_1aZ",
      "is_sender": false,
      "seen": true,
      "sender_id": "ACoAAAcDMMQ",
      "text": "Thanks \u2014 that works for me.",
      "timestamp": "2026-09-21T16:04:11.000Z"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List comment reactions

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List who reacted to a comment. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`comment_id`, text, required): The comment's id, from 'List post comments'.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The reactions on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many reactions there are.

**Example output**

```json
{
  "items": [
    {
      "value": "like"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List comment replies

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List the replies to a comment. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`comment_id`, text, required): The comment's id, from 'List post comments'.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The comments on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many there are.

**Example output**

```json
{
  "items": [
    {
      "id": "cmt_9Hs",
      "text": "Thank you!"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List connections

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List someone's connections. Do not put this on a schedule. Unipile asks specifically that relations are not polled at a fixed time: a request at 8am every day is one of the patterns LinkedIn flags as automation. Do an initial sync, then read the first page a few times a day at irregular intervals.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text): Whose data to read. Use 'me' for the linked account's own. Otherwise a provider id, a handle, or a pasted profile URL. Default: `me`.
- Search (`search`, text): Filter connections by name.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `has_more` (true/false): Whether another page exists.
- `items` (list): The people on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many the provider says exist.

**Example output**

```json
{
  "items": [
    {
      "display_name": "Grace Hopper",
      "id": "ACoAAAcDMMQ"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List drafts

List saved drafts in a mailbox.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- To (`to`, list): Only drafts addressed to these addresses.
- From (`sender`, list): Only drafts from these addresses.
- Anyone involved (`any_email`, list): Only drafts where these addresses appear anywhere.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The drafts.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many drafts there are.

**Example output**

```json
{
  "items": [
    {
      "id": "dr_6Vb",
      "subject": "Draft reply"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List emails

List emails in a mailbox, with filters for sender, recipient, folder, unread and date. Turn on 'Metadata only' for triage workflows: bodies are the bulk of the payload and a step that only reads subjects should not carry them.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Search (`query`, text): Full-text search across the mailbox.
- From (`sender`, list): Only emails from these addresses.
- To (`to`, list): Only emails sent to these addresses.
- Anyone involved (`any_email`, list): Only emails where these addresses appear in any field.
- Folder (`folder`, text): Only emails in this folder.
- Exclude folder (`exclude_folder`, text): Skip emails in this folder.
- Unread only (`is_unread`, true/false): Only unread emails.
- Starred only (`is_starred`, true/false): Only starred emails.
- With attachments (`has_attachment`, true/false): Only emails carrying attachments.
- Received after (`after`, date and time): Only emails after this moment. Use this to poll for new mail.
- Received before (`before`, date and time): Only emails before this moment.
- Metadata only (`meta_only`, true/false): Leave the bodies out, returning only headers and a snippet.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The emails on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many were returned. Not all routes report a total.

**Example output**

```json
{
  "items": [
    {
      "date": "2026-09-21T09:12:00.000Z",
      "id": "em_4Rt",
      "is_unread": true,
      "subject": "Invoice 1042"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List emails in a folder

Works with any mailbox: Gmail, Outlook or IMAP. List the emails inside one folder.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Folder (`folder_id`, text, required): Which mail folder. Pick it from the list, or paste an id.
- Search (`query`, text): Full-text search within the folder.
- Unread only (`is_unread`, true/false): Only unread emails.
- With attachments (`has_attachment`, true/false): Only emails carrying attachments.
- Received after (`after`, date and time): Only emails after this moment.
- Received before (`before`, date and time): Only emails before this moment.
- Metadata only (`meta_only`, true/false): Leave the bodies out.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The emails on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many were returned. Not all routes report a total.

**Example output**

```json
{
  "items": [
    {
      "id": "em_4Rt",
      "subject": "Invoice 1042"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List followers

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List the people following someone. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text): Whose data to read. Use 'me' for the linked account's own. Otherwise a provider id, a handle, or a pasted profile URL. Default: `me`.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `has_more` (true/false): Whether another page exists.
- `items` (list): The people on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many the provider says exist.

**Example output**

```json
{
  "items": [
    {
      "display_name": "Grace Hopper",
      "id": "ACoAAAcDMMQ"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List inbox chats

List conversations in one LinkedIn inbox. This is how you list LinkedIn conversations: the general 'List chats' action is not implemented for LinkedIn and answers with an error pointing here.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Inbox (`inbox_id`, text, required): Which LinkedIn inbox. Classic Primary is the ordinary one; Sales Navigator and Recruiter inboxes appear only with those subscriptions.
- Unread only (`is_unread`, true/false): Only conversations with unread messages.
- Archived only (`is_archived`, true/false): Only archived conversations.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `has_more` (true/false): Whether another page exists.
- `items` (list): The chats on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many the provider says exist.

**Example output**

```json
{
  "items": [
    {
      "id": "chat_8vQ2",
      "is_1to1": true,
      "name": "Grace Hopper",
      "unread_count": 2
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List linked accounts

Any linked account. List the accounts linked to your Unipile application, with each one's connection status. Use this to check an account is still connected before running outreach against it.

**Inputs**

- Network (`provider`, text): Only return accounts on this network. Leave empty for all. One of: `linkedin`, `whatsapp`, `instagram`, `telegram`, `google` (Google (Gmail)), `outlook` (Microsoft (Outlook)), `imap`, `mock` (Mock (Unipile test account)).
- Status (`status`, text): Only return accounts in this connection state. One of: `running`, `errored`, `disconnected`, `degraded`, `partial`.
- Search (`search`, text): Filter by account name.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Offset (`offset`, number): Skip this many results. The account routes page on offset rather than a cursor. At least 0.

**Outputs**

- `has_more` (true/false): Whether another page exists.
- `items` (list): The linked accounts.
- `needs_reconnect` (list): The accounts whose owner must reconnect them in Unipile.
- `needs_reconnect_count` (number): How many are disconnected or errored.
- `total_count` (number): How many were returned.

**Example output**

```json
{
  "has_more": false,
  "items": [
    {
      "created_at": "2026-09-01T09:14:22.000Z",
      "id": "acc_01HZX9",
      "name": "Ada Lovelace",
      "provider": "linkedin",
      "status": "running"
    }
  ],
  "needs_reconnect": [],
  "needs_reconnect_count": 0,
  "total_count": 1
}
```

### List LinkedIn inboxes

List the inboxes available to a LinkedIn account: Classic Primary, Archived, Spam, Jobs, InMail and Starred, plus Sales Navigator and Recruiter inboxes where the subscription allows. LinkedIn has no flat chat list, so this is the entry point to its conversations.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.

**Outputs**

- `items` (list): The inboxes available to this LinkedIn account.
- `total_count` (number): How many inboxes there are.

**Example output**

```json
{
  "items": [
    {
      "description": "Classic Primary inbox",
      "disabled": false,
      "id": "CLASSIC_PRIMARY"
    }
  ],
  "total_count": 1
}
```

### List mail folders

List the mailbox's folders with their total and unread counts.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The folders.
- `total_count` (number): How many folders there are.

**Example output**

```json
{
  "items": [
    {
      "id": "INBOX",
      "is_system": true,
      "name": "Inbox",
      "total_count": 1284,
      "unread_count": 12
    }
  ],
  "total_count": 1
}
```

### List message reactions

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List who reacted to a message, and with what.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The reactions on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many reactions there are.

**Example output**

```json
{
  "items": [
    {
      "author": {
        "id": "ACoAAAcDMMQ",
        "name": "Grace Hopper"
      },
      "value": "\ud83d\udc4d"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List pending invitations

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List pending connection or follow requests, either ones you sent or ones you received. Same caution as listing connections: do not poll this on a fixed schedule.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Direction (`type`, text, required): Invitations you received, or ones you sent. One of: `received`, `sent`. Default: `received`.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The pending requests.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many there are.
- `type` (text): 'sent' or 'received', echoing what was asked for.

**Example output**

```json
{
  "items": [
    {
      "id": "req_5Nx",
      "message": "Let's connect."
    }
  ],
  "next_cursor": null,
  "total_count": 1,
  "type": "received"
}
```

### List post comments

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List the comments on a post. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Sort by (`sort_by`, text): Order the comments come back in. One of: `MOST_RELEVANT` (Most relevant), `MOST_RECENT` (Most recent).
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The comments on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many there are.

**Example output**

```json
{
  "items": [
    {
      "id": "cmt_2Bq",
      "text": "Congratulations!"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List post reactions

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List who reacted to a post, and how. Useful for warm-lead workflows: the people who engaged with a post are the ones worth reaching out to. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The reactions on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many reactions there are.

**Example output**

```json
{
  "items": [
    {
      "author": {
        "id": "ACoAAAcDMMQ",
        "name": "Grace Hopper"
      },
      "value": "like"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### List sender addresses

List the addresses this mailbox can send as, including aliases. Aliases matter for volume: Unipile's guidance is that adding domains as aliases spreads sending reputation across them from one connected mailbox.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.

**Outputs**

- `items` (list): The addresses this mailbox can send as.

**Example output**

```json
{
  "items": [
    {
      "email": "ada@example.com",
      "is_default": true,
      "verification_status": "verified"
    }
  ],
  "total_count": 1
}
```

### List who someone follows

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. List the accounts someone follows. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text): Whose data to read. Use 'me' for the linked account's own. Otherwise a provider id, a handle, or a pasted profile URL. Default: `me`.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `has_more` (true/false): Whether another page exists.
- `items` (list): The people on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): How many the provider says exist.

**Example output**

```json
{
  "items": [
    {
      "display_name": "Grace Hopper",
      "id": "ACoAAAcDMMQ"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### Look up search parameter ids

Turn text into the numeric ids LinkedIn's structured search requires. LinkedIn will not accept 'Los Angeles' as a location filter (it wants 102277331), and this is the only way to find that id. Feed the result into a people or company search.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Kind (`type`, text, required): What kind of id you are looking for. One of: `LOCATION`, `COMPANY`, `RELATION` (Connection), `PEOPLE` (Person), `SCHOOL`, `INDUSTRY`, `SERVICE`, `JOB_FUNCTION` (Job function), `JOB_TITLE` (Job title), `EMPLOYMENT_TYPE` (Employment type), `SKILL`.
- Text (`keywords`, text, required): The text to look an id up for, e.g. 'Los Angeles'.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.

**Outputs**

- `items` (list): The search results on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): What LinkedIn claims exists. Often larger than what can be paged through — LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter).

**Example output**

```json
{
  "items": [
    {
      "id": "102277331",
      "title": "Los Angeles, California, United States"
    }
  ],
  "total_count": 1
}
```

### Mark a message read

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Mark one message as read, as if the account owner had opened it.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.

**Outputs**

- `message_id` (text): The message that was marked.
- `read` (true/false): True when it succeeded.

**Example output**

```json
{
  "message_id": "msg_1aZ",
  "read": true
}
```

### Mark an email read

Works with any mailbox: Gmail, Outlook or IMAP. Mark an email as read.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Email (`email_id`, text, required): The email's id, from 'List emails'.

**Outputs**

- `id` (text): The email that was marked.
- `is_unread` (true/false): The email's unread state after the change.

**Example output**

```json
{
  "id": "em_4Rt",
  "is_unread": false
}
```

### Mark an email unread

Works with any mailbox: Gmail, Outlook or IMAP. Mark an email as unread.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Email (`email_id`, text, required): The email's id, from 'List emails'.

**Outputs**

- `id` (text): The email that was marked.
- `is_unread` (true/false): The email's unread state after the change.

**Example output**

```json
{
  "id": "em_4Rt",
  "is_unread": true
}
```

### Move an email

Works with any mailbox: Gmail, Outlook or IMAP. Move an email by setting which folders it belongs to. Replaces the current set rather than adding to it.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Email (`email_id`, text, required): The email's id, from 'List emails'.
- Folders (`folder_ids`, list, required): The folders the email should be in after the move.

**Outputs**

- `attachments` (list): Files carried by the email.
- `bcc` (list): Bcc recipients.
- `body` (text): Full body. Absent when the call asked for metadata only.
- `cc` (list): Cc recipients.
- `date` (text): When it was sent, ISO 8601.
- `folders` (list): Folders it sits in.
- `from` (list): Sender.
- `id` (text): Unipile's id for the email.
- `is_unread` (true/false): Whether it is still unread.
- `message_id` (text): The RFC 822 Message-ID header.
- `snippet` (text): Short preview of the body.
- `subject` (text): Subject line.
- `thread_id` (text): Groups the email with its replies.
- `to` (list): To recipients.

**Example output**

```json
{
  "folders": [
    "Archive"
  ],
  "id": "em_4Rt"
}
```

### Publish a post

Publish a post to LinkedIn or Instagram. 'Post as' publishes from a company page you administer rather than your own profile.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Text (`text`, text, required): The post's content.
- Attachments (`attachments`, list): Files to send, up to 15 MB each. Upload them here, or reference a document produced by an earlier step.
- Who can see it (`can_read`, text): Post visibility. One of: `anyone`, `relations_only` (Connections only).
- Who can comment (`can_comment`, text): Who is allowed to comment on it. One of: `anyone`, `relations_only` (Connections only), `no_one` (No one).
- Quoting post (`quoted_post_id`, text): The id of a post to quote, to reshare it with commentary.
- Post as company (`post_as`, text): A company page id to publish as, instead of your own profile.

**Outputs**

- `author` (object): Who published it.
- `comments_counter` (number): Total comments.
- `created_at` (text): When it was published.
- `id` (text): The post id.
- `reactions_counter` (number): Total reactions. Null when the provider hides the count.
- `reposts_counter` (number): Total reshares.
- `share_url` (text): Link to the post.
- `text` (text): The post's text.

**Example output**

```json
{
  "id": "post_7Kd",
  "post_url": "https://www.linkedin.com/feed/update/post_7Kd",
  "text": "We are hiring."
}
```

### React to a comment

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. React to a comment on a post. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`comment_id`, text, required): The comment's id, from 'List post comments'.
- Reaction (`reaction`, text, required): The reaction to leave. On LinkedIn this must be a prefixed type: linkedin_like, linkedin_celebrate, linkedin_support, linkedin_love, linkedin_insightful or linkedin_funny. A bare emoji, or a bare 'like', is refused. Other providers take the emoji itself.
- React as company (`react_as`, text): A company page id to react as, instead of your own profile.

**Outputs**

- `comment_id` (text): The comment reacted to.
- `reaction` (text): The reaction that was added.

**Example output**

```json
{
  "comment_id": "cmt_2Bq",
  "reaction": "like"
}
```

### React to a message

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. React to a message with an emoji. Supported on WhatsApp, LinkedIn, Telegram and Instagram.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.
- Reaction (`reaction`, text, required): The reaction to leave. On LinkedIn this must be a prefixed type: linkedin_like, linkedin_celebrate, linkedin_support, linkedin_love, linkedin_insightful or linkedin_funny. A bare emoji, or a bare 'like', is refused. Other providers take the emoji itself.

**Outputs**

- `message_id` (text): The message reacted to.
- `reaction` (text): The reaction that was added.

**Example output**

```json
{
  "message_id": "msg_1aZ",
  "reaction": "\ud83d\udc4d"
}
```

### React to a post

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. React to a post. On LinkedIn the reaction is a named type (like, celebrate, support, love, insightful or funny) rather than an emoji. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Reaction (`reaction`, text, required): The reaction to leave. On LinkedIn this must be a prefixed type: linkedin_like, linkedin_celebrate, linkedin_support, linkedin_love, linkedin_insightful or linkedin_funny. A bare emoji, or a bare 'like', is refused. Other providers take the emoji itself.
- React as company (`react_as`, text): A company page id to react as, instead of your own profile.

**Outputs**

- `post_id` (text): The post reacted to.
- `reaction` (text): The reaction that was added.

**Example output**

```json
{
  "post_id": "post_7Kd",
  "reaction": "like"
}
```

### Remove a comment reaction

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Remove your reaction from a comment.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`comment_id`, text, required): The comment's id, from 'List post comments'.
- Reaction (`reaction`, text, required): Which reaction to remove: the API needs it to know which one is yours. On LinkedIn: linkedin_like, linkedin_celebrate, linkedin_support, linkedin_love, linkedin_insightful or linkedin_funny.

**Outputs**

- `comment_id` (text): The comment reacted to.
- `removed` (true/false): True when the reaction was removed.

**Example output**

```json
{
  "comment_id": "cmt_2Bq",
  "removed": true
}
```

### Remove a message reaction

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Remove your reaction from a message.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`message_id`, text, required): The message's id, from 'List chat messages'.
- Reaction (`reaction`, text, required): Which reaction to remove: the API needs it to know which one is yours. On LinkedIn: linkedin_like, linkedin_celebrate, linkedin_support, linkedin_love, linkedin_insightful or linkedin_funny.

**Outputs**

- `message_id` (text): The message the reaction was removed from.
- `removed` (true/false): True when it succeeded.

**Example output**

```json
{
  "message_id": "msg_1aZ",
  "removed": true
}
```

### Remove a post reaction

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Remove your reaction from a post.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Reaction (`reaction`, text, required): Which reaction to remove: the API needs it to know which one is yours. On LinkedIn: linkedin_like, linkedin_celebrate, linkedin_support, linkedin_love, linkedin_insightful or linkedin_funny.

**Outputs**

- `post_id` (text): The post reacted to.
- `removed` (true/false): True when the reaction was removed.

**Example output**

```json
{
  "post_id": "post_7Kd",
  "removed": true
}
```

### Rename a mail folder

Works with any mailbox: Gmail, Outlook or IMAP. Rename a folder.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Folder (`folder_id`, text, required): Which mail folder. Pick it from the list, or paste an id.
- New name (`name`, text, required): What the folder should be called instead.

**Outputs**

- `id` (text): The folder id.
- `is_system` (true/false): True for built-in folders like Inbox and Sent.
- `name` (text): Folder name as shown in the mailbox.
- `total_count` (number): Emails in the folder.
- `unread_count` (number): Unread emails in the folder.

**Example output**

```json
{
  "id": "Label_42",
  "name": "Invoices 2026"
}
```

### Reply to a comment

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Reply to a comment on a post. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Post (`post_id`, text, required): The post's id, from 'List a person's posts' or a search.
- Comment (`comment_id`, text, required): The comment's id, from 'List post comments'.
- Reply (`text`, text, required): What to say.
- Reply as company (`comment_as`, text): A company page id to reply as, instead of your own profile.

**Outputs**

- `author` (object): Who wrote it.
- `created_at` (text): When it was posted.
- `id` (text): The comment id.
- `reactions_counter` (number): Reactions on the comment.
- `reply_counter` (number): Replies to the comment.
- `text` (text): The comment text.

**Example output**

```json
{
  "id": "cmt_9Hs",
  "text": "Thank you!"
}
```

### Report a profile visit

LinkedIn only. Let someone see that this account viewed their profile: the 'who viewed your profile' notification. Reads the person's profile to get the visit token the endpoint wants, so it spends two of the account's provider actions rather than one.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Person (`person_id`, text, required): Whose profile to report a visit to. Accepts an id, a handle, or a pasted profile URL.
- Visit token (`token`, text): Optional. The 'notify_visit_token' from an earlier 'Get a profile' step: supply it to skip the extra profile read.

**Outputs**

- `person_id` (text): Whose profile was visited.
- `reported` (true/false): True when the visit was reported.

**Example output**

```json
{
  "person_id": "ACoAAAcDMMQ",
  "reported": true
}
```

### Restore a cancelled event

Google and Microsoft calendars only. Un-cancel an event that was cancelled rather than deleted.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- Event (`event_id`, text, required): The event's id, from 'List calendar events'.

**Outputs**

- `cancelled` (true/false): True after a cancel, false after a restore.
- `event_id` (text): The event acted on.

**Example output**

```json
{
  "cancelled": false,
  "event_id": "ev_5Tg"
}
```

### Search LinkedIn companies

Search LinkedIn for companies. Location and industry take numeric ids, as with people search. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Keywords (`keywords`, text): Free-text search terms.
- LinkedIn product (`api`, text): Which product to search through. One of: `classic`, `sales_navigator` (Sales Navigator), `recruiter`.
- Location ids (`location`, list): LinkedIn location ids.
- Industry ids (`industry`, list): LinkedIn industry ids.
- Hiring only (`has_job_postings`, true/false): Only companies with open job postings.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The search results on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): What LinkedIn claims exists. Often larger than what can be paged through — LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter).

**Example output**

```json
{
  "items": [
    {
      "id": "1441",
      "name": "Example Corp"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### Search LinkedIn from a URL

Run a LinkedIn search by pasting a search URL from your browser. The practical way in: LinkedIn's structured search needs its own numeric ids for every filter, and a URL copied from a search, a saved search or a lead list already carries them. LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter), and Unipile recommends keeping total rows fetched per day to the same figure.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Search URL (`url`, text, required): A LinkedIn search, saved search or lead-list URL, copied from the address bar.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The search results on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): What LinkedIn claims exists. Often larger than what can be paged through — LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter).

**Example output**

```json
{
  "items": [
    {
      "id": "ACoAAAcDMMQ",
      "name": "Grace Hopper"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### Search LinkedIn jobs

Search LinkedIn job postings. Classic only. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Keywords (`keywords`, text): Free-text search terms.
- Location ids (`location`, list): LinkedIn location ids.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The search results on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): What LinkedIn claims exists. Often larger than what can be paged through — LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter).

**Example output**

```json
{
  "items": [
    {
      "id": "3901",
      "title": "Staff Engineer"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### Search LinkedIn people

Search LinkedIn for people. The location and industry filters take LinkedIn's own numeric ids, not text: use 'Look up search parameter ids' to turn 'Los Angeles' into the id the search wants, or paste a search URL instead and skip the lookup. LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter), and Unipile recommends keeping the total rows fetched per day to the same figure. This search returns a fixed page that 'Limit' trims: to go past it, chain the cursor from the previous step.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Keywords (`keywords`, text): Free-text search terms.
- LinkedIn product (`api`, text): Which product to search through. One of: `classic`, `sales_navigator` (Sales Navigator), `recruiter`.
- Location ids (`location`, list): LinkedIn location ids, from 'Look up search parameter ids'.
- Industry ids (`industry`, list): LinkedIn industry ids, from 'Look up search parameter ids'.
- Connection degree (`network_distance`, list): 1, 2 or 3: how far from you the person is.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The search results on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): What LinkedIn claims exists. Often larger than what can be paged through — LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter).

**Example output**

```json
{
  "items": [
    {
      "id": "ACoAAAcDMMQ",
      "name": "Grace Hopper"
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### Search LinkedIn posts

Search LinkedIn posts by keyword. Classic only. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Keywords (`keywords`, text): Free-text search terms.
- Limit (`limit`, number): How many to return, 1–250. Keep this small on LinkedIn: every row fetched counts towards the account's daily allowance. From 1 to 250. Default: `50`.
- Cursor (`cursor`, text): Page cursor from a previous run's 'next_cursor'. Leave empty for the first page.

**Outputs**

- `items` (list): The search results on this page.
- `next_cursor` (text): Pass as 'cursor' for the next page.
- `total_count` (number): What LinkedIn claims exists. Often larger than what can be paged through — LinkedIn caps a single query at 1,000 results (2,500 on Sales Navigator or Recruiter).

**Example output**

```json
{
  "items": [
    {
      "id": "post_7Kd",
      "text": "We are hiring."
    }
  ],
  "next_cursor": null,
  "total_count": 1
}
```

### Send a connection request

LinkedIn only. Send a connection request, optionally with a note. The most rate-limited action here. On a paid, active LinkedIn account Unipile's guidance is 80–100 a day and about 200 a week with a note. On a free account it is roughly five a month with a note, or 150 a week without one. Hitting the ceiling returns LinkedIn's own 422 cannot_resend_yet. Space these out and put a delay step between them in any loop.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Person (`person_id`, text, required): Who to act on. Accepts a provider id, a handle, or a pasted profile URL: all three work, so there is no lookup step.
- Note (`message`, text): An optional note, capped at 300 characters by LinkedIn. Sending without a note has a much higher weekly limit.

**Outputs**

- `sent` (true/false): True when the invite went out.
- `user_id` (text): Who was invited.

**Example output**

```json
{
  "sent": true,
  "user_id": "ACoAAAcDMMQ"
}
```

### Send a draft

Works with any mailbox: Gmail, Outlook or IMAP. Send a draft that was saved earlier. The other half of the review-then-send pattern.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Draft (`draft_id`, text, required): The draft's id, from 'List drafts'.

**Outputs**

- `id` (text): Unipile's id for the sent email — use this one.
- `message_id` (text): The RFC Message-ID header, for matching replies.

**Example output**

```json
{
  "id": "em_8Yu",
  "subject": "Draft reply"
}
```

### Send a message or reply

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Reply in a conversation, or send another message into it. This is the reply action for chats: pick the chat with 'Find the chat with a person' or 'List inbox chats'. Counts against the account's provider limits: on WhatsApp, leave at least 10–20 seconds between sends.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Message (`text`, text, required): The message to send.
- Replying to (`quote_id`, text): The id of a message to quote, to send this as a threaded reply.
- Attachments (`attachments`, list): Files to send, up to 15 MB each. Upload them here, or reference a document produced by an earlier step.

**Outputs**

- `chat_id` (text): The chat it went to.
- `message_id` (text): The id of the message that was sent.

**Example output**

```json
{
  "chat_id": "chat_8vQ2",
  "message_id": "msg_1aZ"
}
```

### Send or reply to an email

Send an email from a connected mailbox. Sending limits are the mailbox provider's: Gmail allows 500 a day and Workspace 2,000, but Unipile recommends staying at 50–100 (100–150 on Workspace) to avoid being flagged, starting lower on a new mailbox.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- To (`to`, list, required): Recipient addresses.
- Subject (`subject`, text): Subject line.
- Body (`body`, text): Plain-text body. Set this, the HTML body, or both.
- HTML body (`html`, text): HTML body. Set this, the plain-text body, or both.
- Cc (`cc`, list): Cc addresses.
- Bcc (`bcc`, list): Bcc addresses.
- Reply-to (`reply_to`, list): Addresses replies should go to.
- Replying to (`reply_to_message_id`, text): A message id to reply to, so the email threads correctly.
- From (`sender`, text): Which of the mailbox's addresses to send as. Use 'List sender addresses' to see the aliases available.
- Attachments (`attachments`, list): Files to send, up to 15 MB each. Upload them here, or reference a document produced by an earlier step.
- Track opens (`track_opens`, true/false): Ask Unipile to report when the email is opened. Needs an HTML body: the tracking pixel has nowhere to go in plain text.
- Track clicks (`track_clicks`, true/false): Ask Unipile to report when a link is clicked. Needs an HTML body, since tracking works by rewriting the links in it.

**Outputs**

- `id` (text): Unipile's id for the sent email — use this one.
- `message_id` (text): The RFC Message-ID header, for matching replies.

**Example output**

```json
{
  "id": "em_8Yu",
  "subject": "Re: Invoice 1042"
}
```

### Set presence

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Set the account's online presence. Like the typing indicator, this is part of behaving like a person rather than a script.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Presence (`presence`, text, required): How the account should appear to others. One of: `online`, `restricted_online` (Online (restricted)), `away`, `offline`.

**Outputs**

- `presence` (text): The presence that was set.

**Example output**

```json
{
  "presence": "online"
}
```

### Set typing indicator

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Show the 'typing…' or 'recording audio…' indicator in a conversation. Worth more than it looks: Unipile's guidance for staying under a provider's automation radar is to behave like a person, and a message that appears with no typing indicator before it does not. The indicator clears on its own: there is no 'stop' to send.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Action (`indicator`, text, required): Which indicator to show. LinkedIn only takes 'typing'; 'recording' is for the providers that carry voice notes. One of: `typing`, `recording` (Recording audio).

**Outputs**

- `action` (text): The indicator state that was set.
- `chat_id` (text): The chat that was updated.

**Example output**

```json
{
  "action": "start",
  "chat_id": "chat_8vQ2"
}
```

### Start a chat from an inbox

Start a conversation from a specific LinkedIn inbox and send the first message. This is the route LinkedIn uses for a new chat ('Start a chat' is not implemented there), and it is also how you send from Sales Navigator or Recruiter rather than from Classic. A new chat is only possible with an existing connection unless it goes as an InMail, which spends one of the account's InMail credits. Counts against the account's provider limits: Unipile's guidance is roughly 100 of these per day per LinkedIn account, spaced out rather than chained. Exceeding it risks a warning on the account.

**Inputs**

- Account (`account_id`, text, required): Which linked LinkedIn account to act as. Every limit below applies to this real LinkedIn account, not to an API quota.
- Inbox (`inbox_id`, text, required): Which LinkedIn inbox. Classic Primary is the ordinary one; Sales Navigator and Recruiter inboxes appear only with those subscriptions.
- Recipients (`user_ids`, list, required): Who to message. Give a provider id, a handle, or paste a profile URL. One person starts a 1:1; several start a group. On LinkedIn you can only start a chat with an existing connection unless you send it as an InMail.
- Message (`text`, text, required): The first message to send.
- Attachments (`attachments`, list): Files to send, up to 15 MB each. Upload them here, or reference a document produced by an earlier step.

**Outputs**

- `chat_id` (text): The chat it went to.
- `message_id` (text): The id of the message that was sent.

**Example output**

```json
{
  "chat_id": "chat_8vQ2",
  "message_id": "msg_1aZ"
}
```

### Trash an email

Works with any mailbox: Gmail, Outlook or IMAP. Move an email to the trash folder.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Email (`email_id`, text, required): The email's id, from 'List emails'.

**Outputs**

- `id` (text): The email that was trashed.
- `trashed` (true/false): True when it was trashed.

**Example output**

```json
{
  "id": "em_4Rt",
  "trashed": true
}
```

### Unfollow a person

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Stop following someone.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Person (`person_id`, text, required): Who to act on. Accepts a provider id, a handle, or a pasted profile URL: all three work, so there is no lookup step.

**Outputs**

- `following` (true/false): True after a follow, false after an unfollow.
- `user_id` (text): Who was followed.

**Example output**

```json
{
  "following": false,
  "user_id": "ACoAAAcDMMQ"
}
```

### Update a calendar

Rename or re-describe a calendar. Only the fields you set are changed.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- Name (`name`, text): New name.
- Description (`description`, text): New description.
- Timezone (`timezone`, text): New IANA timezone.

**Outputs**

- `description` (text): Calendar description.
- `id` (text): The calendar id.
- `is_default` (true/false): Whether this is the account's default calendar.
- `is_owned_by_user` (true/false): Whether the account owns it, rather than subscribing.
- `is_read_only` (true/false): True when events cannot be written here.
- `name` (text): Calendar name.
- `timezone` (text): The calendar's IANA timezone.

**Example output**

```json
{
  "id": "cal_2Lm",
  "name": "Interviews 2026"
}
```

### Update a calendar event

Google and Microsoft calendars only. Change an existing event. Only the fields you set are changed.

**Inputs**

- Account (`account_id`, text, required): Which linked calendar to act as: a Google or Microsoft account. IMAP mailboxes are not offered here: IMAP carries mail only and has no calendar. Accounts are linked in your Unipile dashboard, not here.
- Calendar (`calendar_id`, text, required): Which calendar. Pick it from the list, or paste an id.
- Event (`event_id`, text, required): The event's id, from 'List calendar events'.
- Title (`title`, text): New title.
- Start (`start`, date and time): New start time.
- End (`end`, date and time): New end time.
- Description (`body`, text): New description.
- Location (`location`, text): New location.
- Guests (`attendees`, list): The full guest list after the change: this replaces the existing one.
- Timezone (`timezone`, text): IANA timezone for the times above.
- Notify guests (`notify`, text): Who gets told about the change. One of: `all` (Notify everyone), `externalOnly` (Notify external guests only), `none` (Notify no one).

**Outputs**

- `attendees` (list): Invitees and their responses.
- `body` (text): Event description.
- `end` (text): End, ISO 8601.
- `id` (text): The event id.
- `is_cancelled` (true/false): Whether it has been cancelled.
- `location` (text): Where it takes place.
- `start` (text): Start, ISO 8601.
- `title` (text): Event title.

**Example output**

```json
{
  "id": "ev_5Tg",
  "title": "Design review (moved)"
}
```

### Update a chat

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Rename, pin, archive, mute, label or mark a conversation read. Only the fields you set are changed. Treat archiving as one-way: un-archiving sets the chat's own flag back, but the conversation can keep being listed under the archived inbox rather than Classic Primary, so anything downstream should find it by person rather than by listing an inbox.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- Chat (`chat_id`, text, required): The conversation's id, from 'List chats'. Not a dropdown: an account can have tens of thousands of conversations, which is the wrong size for a picker.
- Name (`name`, text): Rename the conversation. Groups only.
- Label (`label`, text): Set the conversation's label, where the provider supports one.
- Mark read (`read_status`, true/false): True marks the conversation read, false marks it unread.
- Pinned (`pin_status`, true/false): True pins the conversation, false unpins it.
- Archived (`archive_status`, true/false): True archives the conversation, false restores it.
- Muted until (`muted_until`, date and time): Mute notifications until this moment.

**Outputs**

- `id` (text): The chat id, used by every message action.
- `is_1to1` (true/false): True for a direct conversation.
- `is_archived` (true/false): Whether the owner archived it.
- `is_group` (true/false): True for a group conversation.
- `last_message_timestamp` (text): When the most recent message landed.
- `name` (text): Group name, or the other person's name in a 1:1.
- `participants_count` (number): How many people are in it.
- `provider` (text): Which network the chat is on.
- `type` (text): The chat's kind, as the provider classifies it.
- `unread_count` (number): Unread messages in this chat.

**Example output**

```json
{
  "id": "chat_8vQ2",
  "is_archived": true
}
```

### Update a draft

Works with any mailbox: Gmail, Outlook or IMAP. Edit a saved draft.

**Inputs**

- Account (`account_id`, text, required): Which linked mailbox to act as: Gmail, Outlook or IMAP. Mailboxes are linked in your Unipile dashboard, not here.
- Draft (`draft_id`, text, required): The draft's id, from 'List drafts'.
- To (`to`, list): Recipient addresses.
- Subject (`subject`, text): Subject line.
- Body (`body`, text): Plain-text body.
- HTML body (`html`, text): HTML body.
- Cc (`cc`, list): Cc addresses.
- Bcc (`bcc`, list): Bcc addresses.
- Attachments (`attachments`, list): Files to send, up to 15 MB each. Upload them here, or reference a document produced by an earlier step.

**Outputs**

- `body` (text): The draft body.
- `id` (text): The draft id.
- `subject` (text): Subject line.
- `to` (list): To recipients.

**Example output**

```json
{
  "id": "dr_6Vb",
  "subject": "Draft reply (v2)"
}
```

### Update your profile

Works with any messaging account: LinkedIn, WhatsApp, Instagram or Telegram. Edit the linked account's own profile. Only the fields you set are changed, but on LinkedIn only 'Bio' and 'Location' can be: it refuses first name, last name and headline, and the refusal is all-or-nothing, so setting one of those leaves everything unchanged rather than applying the rest.

**Inputs**

- Account (`account_id`, text, required): Which linked messaging account to act as: LinkedIn, WhatsApp, Instagram or Telegram. Accounts are linked in your Unipile dashboard, not here.
- First name (`first_name`, text): New given name.
- Last name (`last_name`, text): New family name.
- Headline (`description`, text): New headline: the one-line summary under your name.
- About (`bio`, text): New longer profile text.
- Location (`location`, text): New location.

**Outputs**

- `person_id` (text): Whose profile changed.
- `updated` (true/false): True when the change was applied.

**Example output**

```json
{
  "description": "Building things at Lodol",
  "id": "ACoAAAcDMMQ"
}
```
