Expandi
Work your Expandi LinkedIn outreach: senders, campaigns and each lead's state, message threads, searches, and scheduled messages, invitations and posts. Connect with an API key and secret.
- rest
https://api.superagnt.com/v1/connections/expandiplus the vendor's own path, with your superagnt_ API key asAuthorization: Bearer.- mcp
- Tools named
connection_expandi_*onhttps://mcp.superagnt.com/mcp, served once the account is connected. - billing
- Expandi bills your own account. Calls cost no superagnt_ data credits.
- rate limit
- 5 requests a second, 300 a minute: the vendor's ceiling as the registry records it, for sizing bursts. Your plan's own limit is on Connections.
- vendor docs
- https://api.liaufa.com/open-swagger/
- sync
- Can copy 5 tables into your workspace database and keep them fresh: the tables.
The Expandi connection lets an agent work the LinkedIn outreach you already run in Expandi. It lists your LinkedIn accounts (senders) and checks each one is connected, reads each account's campaigns with their stats, reads every lead's connection and conversation state and its message thread, adds, pauses or removes a contact in a campaign, keeps searches (lead lists), followed keywords and the blacklist up to date, and schedules single actions: LinkedIn messages, connection requests, emails, open InMails, profile visits, post reactions and comments, and posts.
the key reaches everything its user can
An Expandi API key belongs to a user, not to one LinkedIn account: agents can reach every workspace, company and LinkedIn account that user can access in Expandi. Connect a user whose access matches what agents should work on.
01
Setup
- Generate a key and secret. In Expandi open Account Settings, select your default workspace, and under Expandi API keys click Generate. Copy both the key and the secret.
- Connect Expandi. In the superagnt app open Integrations, pick Expandi, and paste the API key and the API secret. Both are required.
02
Things to know
- Workspace, companies, LinkedIn accounts. Companies group LinkedIn accounts inside a workspace, and one seat is one LinkedIn account (
connection_expandi_workspace_readactionsubscriptionsshows seats used and available). - Almost everything hangs off one LinkedIn account. Start with
connection_expandi_linkedin_accounts_read(actionlist) and pass an account'sidasli_account_idto the campaign, lead, search, keyword and action tools. - Messengers are leads. Expandi calls the relationship between a lead and a LinkedIn account a messenger.
connection_expandi_campaigns_readactioncontactsreturns each lead'scontact,contact_status,conversation_status,invited_at,connected_at,last_datetimeandhas_new_messages, filtered bycampaign_instance_id,search_filter_idorprofile_link. Actionmessagesreturns one messenger's full thread. - Campaigns are campaign instances, each with a type, a status, a contact count and a
statssnapshot. Sequence step content is not readable through the API. - Check the sender first. Nothing runs from a LinkedIn account that is disconnected or stuck on a login challenge. Action
statusonconnection_expandi_linkedin_accounts_readshowsstatus_codeand anypending_challenge(a PIN, a phone number, an app confirmation or a new password), which only the account owner can clear, in the Expandi app. - Actions run later. A scheduling call returns an action id at once, and Expandi performs the action from the real LinkedIn account inside the daily limits and working hours set for it in Expandi. Action
action_statusreports how it went (it cannot report a comment or a post): pass theaction_idthe scheduling call returned and itstype(mfor a message,crfor a connection request, and so on). - No date filters. Lists page by number (
page, from 1) and returncount,nextandprevious. No list filters by date or sorts, so to find what changed, walk every page and compareupdated. - A wrong key or secret hangs. Expandi does not refuse a bad key or secret: it holds the request for 30 seconds or more. superagnt_ waits up to 60 seconds and never retries, so a timeout on a new connection usually means a mistyped key or secret. Expandi reports other failures as HTTP 400 with
{"error": "..."}, which an MCP tool result carries inupstreamError. - Some fields are objects. Expandi's own spec types several fields as strings that are really nested objects (
contact,stats,placeholders). Read them as JSON. - The blacklist is write-only. Entries cannot be read or removed through the API, and
clear: truereplaces the existing entries of the same field and match type. - Rate limits. Expandi publishes no API rate limit. LinkedIn actions are paced by each account's limits in Expandi.
- The connection does not cover adding a LinkedIn account to Expandi (it takes the LinkedIn password and two-factor secret), the LinkedIn login flow and its challenges, or Expandi's legacy v1 routes.
03
Permissions
These defaults decide whether a superagnt_ agent runs a call or waits for a person (Permissions). Reads run without asking, and so do checking an action's status, creating an empty search and following keywords. Profile visits, changing a scheduled post, adding a contact to a search and blacklisting ask by default. Sending a LinkedIn message, connection request, email or open InMail, reacting to or commenting on a post, scheduling a post, adding, pausing or resuming a contact in a campaign, and every removal (a campaign contact, a search contact, a scheduled post, a followed keyword) always ask a person first.
04
Examples
List LinkedIn accounts
curl "https://api.superagnt.com/v1/connections/expandi/li_accounts/" \
-H "Authorization: Bearer $AGNTDATA_API_KEY"Read the leads in one campaign
curl "https://api.superagnt.com/v1/connections/expandi/li_accounts/$LI_ACCOUNT_ID/messengers/?campaign_instance_id=$CAMPAIGN_ID&page=1" \
-H "Authorization: Bearer $AGNTDATA_API_KEY"Read a lead's message thread
curl "https://api.superagnt.com/v1/connections/expandi/li_accounts/messengers/$MESSENGER_ID/messages/" \
-H "Authorization: Bearer $AGNTDATA_API_KEY"Add a contact to a campaign with placeholders
curl -X POST "https://api.superagnt.com/v1/connections/expandi/li_accounts/campaign_instances/$CAMPAIGN_ID/create_contact/" \
-H "Authorization: Bearer $AGNTDATA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profile_link": "https://www.linkedin.com/in/ada-lovelace/",
"placeholders": { "icebreaker": "Loved your talk on analytical engines" }
}'From an agent, adding a campaign contact always asks a person first: in an active campaign the sequence starts reaching out to the contact from the real LinkedIn account.
05
Receiving Expandi webhooks
Expandi webhooks can only be created in the Expandi app, per LinkedIn account (LinkedIn Settings → Webhooks), so agents cannot register them. To trigger an agent when a lead replies or accepts a connection request, create the webhook in Expandi and point it at a superagnt_ inbound webhook endpoint. Expandi signs nothing and does not retry, so use an endpoint URL nobody can guess.
06
Sync
An Expandi sync copies your LinkedIn accounts, campaigns, leads and their message threads into tables in your workspace database and keeps them fresh, so agents read local tables instead of paging Expandi on every run. Turn it on from the Sync panel on the Expandi connection page in the superagnt app. The panel previews the rows and webhook events against your plan before anything is created. How syncs work in general: Vendor sync.
How updates arrive. Expandi's API has no date filter and no ordering, so every pass re-reads the selected accounts' lists (hourly by default) and keeps only what changed. A campaign or lead that disappears at Expandi is marked deleted, and messages are re-read for each lead whose last activity moved. Webhook deliveries are stored whole in expandi_events and also make the sync re-read the leads, so a reply shows up without waiting for the hourly pass.
Set up the webhooks in Expandi. Expandi webhooks are created by hand, per LinkedIn account. Once the sync is on, the Sync panel shows its webhook URL in a copyable field next to these steps (on a workspace MCP connection, agnt_sync_status returns it as ingest_url):
- Open the webhook settings. In Expandi, open a LinkedIn account's menu, then LinkedIn Settings, then Webhooks.
- Pick an event. Click +Add a webhook and pick an event. We suggest Contact replied and Connection request accepted.
- Paste the URL. Paste the URL from the Sync panel, click Send test, then Create webhook.
- Repeat per account. Repeat for every LinkedIn account you want synced in real time. Accounts without the webhook still sync on the regular schedule.
Expandi signs nothing and never retries, and a webhook fires only for actions after it was created, so events missed while a webhook is off are lost from expandi_events (the leads and their threads still sync by polling). The Sync panel says so when deliveries stop while the leads keep changing. Turning the sync off and on again issues a new URL to paste.
Plans and scope.
- With a wrong key or secret, Expandi never answers. The sync's credential check waits 20 seconds, then says to check both and reconnect.
- One key spans every Expandi workspace and LinkedIn account its user can reach. The workspace and LinkedIn account filters narrow the sync.
- The sync only reads. It never sends a message, an invitation or any other LinkedIn action.
- Expandi publishes no rate limit, so the sync paces itself at 60 requests a minute.
What a Expandi sync copies
A sync copies these tables into your workspace database and keeps them fresh, so an agent reads local rows instead of calling Expandi on every run. Turn tables on and off from the Sync panel on the connection. Every table also carries _raw, _hash, _synced_at and _deleted_at. How syncs work: Vendor sync.
beta
_raw column.| Table | What it holds | Default |
|---|---|---|
expandi_li_accountsLinkedIn accounts | The LinkedIn accounts (senders) of each synced workspace, re-read every hour. | on |
expandi_campaignsCampaigns | The campaigns of each synced LinkedIn account with their status, contact count and Expandi stats, re-read every hour. | on |
expandi_messengersLeads | One row per lead of each synced LinkedIn account (Expandi calls it a messenger), with its connection and conversation status, re-read every hour. | on |
expandi_messagesMessages | The LinkedIn messages of the synced leads, read again whenever a lead shows new activity. Kept for 90 days by default. | on |
expandi_eventsWebhook events | One row per webhook delivery from Expandi, stored whole: the only record of individual visits, invitations, likes and email events, and only from the moment a webhook is set up. Kept for 90 days by default. | on |
14 tools, one per resource and risk
MCP servers and agents on the grouped surface list Expandi as these tools. Each takes an action, and the ones that work across record types an object. Every operation also keeps its own per-operation name, in the next table, which works on every server. How grouping works: Grouped tools.
| Tool | Risk | Actions |
|---|---|---|
connection_expandi_workspace_readRead Expandi workspaces, companies and seats List the workspaces the key's user can reach, the companies (groups of LinkedIn accounts) inside them, or the active subscriptions with their seats (one seat is one LinkedIn account). | read | workspacescompaniessubscriptions |
connection_expandi_linkedin_accounts_readRead Expandi LinkedIn accounts List the LinkedIn accounts (senders) the key's user can reach (almost every other call takes one's id as li_account_id), check whether one is connected and working, or check how an action scheduled from it went. A login challenge (a PIN or a new password) can only be resolved by the account owner in the Expandi app. | read | liststatusaction_status |
connection_expandi_campaigns_readRead Expandi campaigns, contacts and messages List one LinkedIn account's campaigns with their status and stats, page through the contacts the account is working (Expandi calls them messengers) with each one's campaign and conversation state, or read the message thread with one contact. Sequence step content is not readable through the API. | read | listcontactsmessages |
connection_expandi_campaign_contacts_writeAdd, pause or resume Expandi campaign contacts Add the person behind a LinkedIn profile URL to a campaign, with per-contact placeholder values, or pause or resume one contact. In an active campaign, an added or resumed contact gets the sequence (connection requests, messages, emails) from the real LinkedIn account. | write | addset_active |
connection_expandi_campaign_contacts_deleteRemove a contact from an Expandi campaign Remove a contact from a campaign by LinkedIn profile URL, so the campaign stops reaching out to them. Not undoable through the API. | destructive | remove |
connection_expandi_messages_sendSend Expandi messages and connection requests Schedule a LinkedIn message (1st-degree connections only), a connection request with an optional note, an email through the mailbox connected to the account, or an open InMail to an Open Profile member, from a LinkedIn account. Each reaches a real person, so get the user's sign-off first; on a deployed agent, each asks for approval by default. Scheduling returns an action id at once: check it with connection_expandi_linkedin_accounts_read action "action_status". | write | messageconnection_requestemailopen_inmail |
connection_expandi_engagement_writeVisit profiles and engage with LinkedIn posts in Expandi Schedule a profile visit (LinkedIn may show the person who viewed them), a reaction to a post with an optional comment, or a comment on a post, from a LinkedIn account. Reactions and comments are public. Check a visit or reaction with connection_expandi_linkedin_accounts_read action "action_status". | write | visitreactcomment |
connection_expandi_posts_readRead Expandi posts and followed keywords List the posts a LinkedIn account authored, its posts scheduled through the API and still waiting, the keywords it follows, or the LinkedIn posts Expandi collected for one followed keyword. | read | listscheduledkeywordskeyword_posts |
connection_expandi_posts_writeSchedule Expandi posts and follow keywords Schedule a post to publish from a LinkedIn account at send_datetime, change a post still waiting, or follow keywords so Expandi collects posts that mention them. A published post is public and can no longer be changed or deleted here. | write | scheduleupdate_scheduledfollow_keywords |
connection_expandi_posts_deleteDelete an Expandi scheduled post or unfollow keywords Delete a post still waiting to be published, or stop a LinkedIn account following keywords. | destructive | delete_scheduledunfollow_keywords |
connection_expandi_searches_readRead Expandi searches List one LinkedIn account's searches (Expandi's lead lists) with their criteria, result counts and the campaigns they feed. | read | list |
connection_expandi_searches_writeCreate and fill Expandi searches Create an empty search (lead list) on a LinkedIn account, or add the person behind a profile URL to one. A search can feed campaigns, which may then start working the contact. Searches cannot be deleted through the API. | write | createadd_contact |
connection_expandi_searches_deleteRemove a contact from an Expandi search Remove a contact from a search (lead list) by LinkedIn profile URL. | destructive | remove_contact |
connection_expandi_blacklist_writeBlacklist people in Expandi Add blacklist entries for one LinkedIn account or one company so Expandi never contacts matching people, by name, company, job title, profile link or email. clear: true replaces the existing entries of that field and match type, so the people they excluded can be contacted again. Entries cannot be read or removed through the API. | write | add |
All 33 operations
Each operation is a REST path under https://api.superagnt.com/v1/connections/expandi and an MCP tool. The per-operation tool name is the one permissions, approvals and usage records use.
| Operation | MCP tool |
|---|---|
GET /workspaces/List workspaces | connection_expandi_list_workspacesgrouped: connection_expandi_workspace_read, action workspaces |
GET /companies/List companies | connection_expandi_list_companiesgrouped: connection_expandi_workspace_read, action companies |
GET /subscriptions/List subscriptions and seats | connection_expandi_list_subscriptionsgrouped: connection_expandi_workspace_read, action subscriptions |
GET /li_accounts/List LinkedIn accounts | connection_expandi_list_linkedin_accountsgrouped: connection_expandi_linkedin_accounts_read, action list |
GET /li_accounts/{li_account_id}/status/Get a LinkedIn account's connection status | connection_expandi_get_linkedin_account_statusgrouped: connection_expandi_linkedin_accounts_read, action status |
GET /li_accounts/{li_account_id}/campaign_instances/List a LinkedIn account's campaigns | connection_expandi_list_campaign_instancesgrouped: connection_expandi_campaigns_read, action list |
POST /li_accounts/campaign_instances/{campaign_instance_id}/create_contact/Add a contact to a campaign | connection_expandi_add_campaign_contactgrouped: connection_expandi_campaign_contacts_write, action add |
PATCH /li_accounts/campaign_instances/{campaign_instance_id}/update_contact/Pause or resume a contact in a campaign | connection_expandi_update_campaign_contactgrouped: connection_expandi_campaign_contacts_write, action set_active |
DELETE /li_accounts/campaign_instances/{campaign_instance_id}/delete_contact/Remove a contact from a campaign | connection_expandi_remove_campaign_contactgrouped: connection_expandi_campaign_contacts_delete, action remove |
GET /li_accounts/{li_account_id}/messengers/List a LinkedIn account's leads (messengers) | connection_expandi_list_messengersgrouped: connection_expandi_campaigns_read, action contacts |
GET /li_accounts/messengers/{messenger_id}/messages/List the messages with one lead | connection_expandi_list_messagesgrouped: connection_expandi_campaigns_read, action messages |
POST /li_accounts/{li_account_id}/actions/message/Send a LinkedIn message | connection_expandi_schedule_messagegrouped: connection_expandi_messages_send, action message |
POST /li_accounts/{li_account_id}/actions/connection_request/Send a connection request | connection_expandi_schedule_connection_requestgrouped: connection_expandi_messages_send, action connection_request |
POST /li_accounts/{li_account_id}/actions/email/Send an email to a lead | connection_expandi_schedule_emailgrouped: connection_expandi_messages_send, action email |
POST /li_accounts/{li_account_id}/actions/open_imail/Send an open InMail | connection_expandi_schedule_open_inmailgrouped: connection_expandi_messages_send, action open_inmail |
POST /li_accounts/{li_account_id}/actions/visit/Visit a LinkedIn profile | connection_expandi_schedule_profile_visitgrouped: connection_expandi_engagement_write, action visit |
POST /li_accounts/{li_account_id}/actions/post_like/React to a LinkedIn post | connection_expandi_schedule_post_likegrouped: connection_expandi_engagement_write, action react |
POST /li_accounts/{li_account_id}/actions/comment/Comment on a LinkedIn post | connection_expandi_schedule_post_commentgrouped: connection_expandi_engagement_write, action comment |
POST /li_accounts/{li_account_id}/actions/schedule_post/Schedule a LinkedIn post | connection_expandi_schedule_postgrouped: connection_expandi_posts_write, action schedule |
GET /li_accounts/{li_account_id}/actions/scheduled_posts/List scheduled posts | connection_expandi_list_scheduled_postsgrouped: connection_expandi_posts_read, action scheduled |
PATCH /li_accounts/actions/scheduled_posts/{scheduled_post_id}/update/Change a scheduled post | connection_expandi_update_scheduled_postgrouped: connection_expandi_posts_write, action update_scheduled |
DELETE /li_accounts/actions/scheduled_posts/{scheduled_post_id}/delete/Delete a scheduled post | connection_expandi_delete_scheduled_postgrouped: connection_expandi_posts_delete, action delete_scheduled |
POST /li_accounts/actions/{li_account_id}/check_action_status/Check a scheduled action's status | connection_expandi_get_action_statusgrouped: connection_expandi_linkedin_accounts_read, action action_status |
GET /li_accounts/{li_account_id}/searches/List a LinkedIn account's searches | connection_expandi_list_searchesgrouped: connection_expandi_searches_read, action list |
POST /li_accounts/{li_account_id}/searches/create/Create an empty search | connection_expandi_create_searchgrouped: connection_expandi_searches_write, action create |
POST /li_accounts/searches/{search_id}/create_contact/Add a contact to a search | connection_expandi_add_search_contactgrouped: connection_expandi_searches_write, action add_contact |
DELETE /li_accounts/searches/{search_id}/delete_contact/Remove a contact from a search | connection_expandi_remove_search_contactgrouped: connection_expandi_searches_delete, action remove_contact |
GET /li_accounts/{li_account_id}/keywords/list/List followed keywords | connection_expandi_list_followed_keywordsgrouped: connection_expandi_posts_read, action keywords |
POST /li_accounts/{li_account_id}/keywords/Follow keywords | connection_expandi_follow_keywordsgrouped: connection_expandi_posts_write, action follow_keywords |
DELETE /li_accounts/{li_account_id}/keywords/delete/Unfollow keywords | connection_expandi_unfollow_keywordsgrouped: connection_expandi_posts_delete, action unfollow_keywords |
GET /li_accounts/{li_account_id}/keywords/posts/List posts for a followed keyword | connection_expandi_list_keyword_postsgrouped: connection_expandi_posts_read, action keyword_posts |
GET /li_accounts/{li_account_id}/posts/List the account's own posts | connection_expandi_list_account_postsgrouped: connection_expandi_posts_read, action list |
POST /blacklists/Add blacklist entries | connection_expandi_add_blacklist_entriesgrouped: connection_expandi_blacklist_write, action add |