Skip to content
ProspectAPIs

API guide

Connect your account

Written and maintained by The ProspectAPIs team

A connected account is a LinkedIn account of your own, linked to your ProspectAPIs key so the actions you call run as you: messages, invites, follows, visits, posts, reactions, comments and reposts, plus the followers of a page you administer. Connecting, checking and disconnecting are free. One account per ProspectAPIs account; connecting again replaces the one before.

The four routes

RouteWhat it does
POST /v1/accounts/sessionConnect with the account's signed-in session string. Checked live once, then stored.
POST /v1/accounts/loginConnect by signing in with the account's email or phone and password.
GET /v1/accounts/sessionWhat is connected: active or dead, handle, name and dates. Never the session.
DELETE /v1/accounts/sessionDisconnect: the stored session is deleted. Safe to repeat, works at a zero balance.

Connect with a session string

Sign in to the account in your own browser, copy its session string, and send it once. We check it live, read the account's handle and name, and answer 201 with what is connected. A signed-out session answers 422 session_logged_out and nothing is stored.

bash
curl -X POST https://api.prospectapis.com/v1/accounts/session \
  -H "Authorization: Bearer $PROSPECTAPIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"session": "<the account session string>"}'

Two optional fields: proxy_url, your own http, https or socks5 address for this account (it must be a public address), and user_agent, the browser the session was created in.

Every connected account acts through its own dedicated IP unless you bring your own proxy. The egress field says which: dedicated (an IP leased to this account alone), shared_fallback (a shared IP, used only while every dedicated IP is taken), customer_proxy (your own proxy_url) or none. Only when no dedicated and no shared IP is free and you sent no proxy_url does connecting answer 503 egress_unavailable; nothing is stored, so try again shortly, or connect with your own proxy.

Connect by signing in

Send the account's email or phone and password. If the account asks for one more step, the answer is a 409 with a challenge_id: a two-factor code, a code sent by email, or a check a person must finish at handoff_url. Send the same request again with code and challenge_id within 15 minutes. Unless you opt in below, the password is used for that sign-in only.

bash
curl -X POST https://api.prospectapis.com/v1/accounts/login \
  -H "Authorization: Bearer $PROSPECTAPIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "jane@example.com", "password": "<password>"}'

# 409 {"code": "two_factor_required", "challenge_id": "..."}
curl -X POST https://api.prospectapis.com/v1/accounts/login \
  -H "Authorization: Bearer $PROSPECTAPIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "jane@example.com", "password": "<password>", "code": "123456", "challenge_id": "..."}'

When the account belongs to your own user, do not ask them for their password. Create a connect link and send it to them: they open it on prospectapis.com, sign in there (with any code or check the account asks for) or paste a session string, and are sent back to you. You never see or store their password.

bash
curl -X POST https://api.prospectapis.com/v1/accounts/connect-link \
  -H "Authorization: Bearer $PROSPECTAPIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "crm-user-42", "success_redirect_url": "https://app.example.org/connected", "notify_url": "https://hooks.example.org/prospect"}'

# 201 {"link_id": "...", "url": "https://prospectapis.com/connect#cl_...", "expires_on": "...", "webhook_secret": "whsec_..."}

A link works once and expires after one hour, or at expires_on (5 minutes to 24 hours). We store only a hash of it, and its token sits after the #, so no server log ever holds it. Revoking the API key that made it ends it, and so does DELETE /v1/accounts/connect-link/:link_id. After ten sign-in attempts it stops working. type: "reconnect" with an account_id reconnects that account and keeps its id. name is your own reference for the account: it comes back on the redirect (with status, account_id and, on failure, reason) and in every event.

With notify_url, that account's events go there: account.connected (each time it connects), account.reconnect_required (the platform signed it out) and account.disconnected (it was removed). Each is signed like a watchlist delivery, Prospect-Signature: t=<unix>,v1=<hex>, an HMAC-SHA256 of <t>.<body> keyed with the webhook_secret shown once when you made the link. An account without its own notify_url gets account.reconnect_required on your active watchlists' webhooks.

Two-factor codes and automatic re-login

Add totp_secret, your authenticator app's setup key (the text under the QR code when you turn on two-factor sign-in), and the code is typed during the sign-in, so you never see the 409. Add "remember": true and we keep the sign-in details encrypted: when the platform signs the account out, it is signed back in on its own dedicated connection, and calls carry on. If that cannot finish (a check only you can complete, or a changed password), you get one email a day with a link to reconnect. Disconnecting deletes the details; a connect without remember clears an earlier opt-in.

bash
curl -X POST https://api.prospectapis.com/v1/accounts/login \
  -H "Authorization: Bearer $PROSPECTAPIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "jane@example.com", "password": "<password>", "totp_secret": "<setup key>", "remember": true}'

Writes while the account is signed out

If the platform has signed your account out, or it needs a reconnect, a write is not lost: it answers 202 with {"status": "queued", "queued_id": "..."} and is sent, through the same pacing, once the account is connected again. It is charged only when it is sent. At most 50 writes wait per account, an identical write is queued once, and a write left queued for 72 hours expires. GET /v1/writes/queued lists them and DELETE /v1/writes/queued/:id cancels one; both are free. An account that was never connected is refused, not queued.

A queued write is sent only from the account it was queued under: if a different account is connected by then, it finishes with outcome account_changed and is not sent. Disconnecting the account cancels every write still waiting. A send whose answer is lost after it may have reached the platform finishes as outcome_unknown and is never sent twice, so check the account before sending it again yourself.

Conversations, attachments and reactions

Beyond a direct message, the connected account can start a conversation, attach a file, message someone outside its network, react to a message and mark a thread read. Each action below is listed with its price at GET /pricing and answers 503 temporarily_unavailable, with nothing charged, until it is switched on.

RouteWhat it does
POST /v1/chatsStart a conversation with one person or a group of up to 50, with an optional attachment. Answers the new thread_id.
POST /v1/messagesA direct message, now with an optional attachment, or inmail: true with a subject for someone outside the network (one credit; 409 no_inmail_credits when none is left).
POST /v1/messages/reactAdd an emoji to one message in a thread, or remove it.
POST /v1/messages/readMark a thread read.
GET /v1/messages/inmail-creditsThe account's remaining credits for messages outside its network. Free.

An attachment is one file of at most 20 MB: a PDF, Word, PowerPoint or Excel document, plain text, or a JPEG, PNG or GIF image. Send it as { "url": "https://..." }, a public https address that answers the file itself, or as data in base64 with its filename and mime_type. A file we cannot fetch is 422 attachment_unreachable and one we do not accept is 400 attachment_not_accepted; neither is charged. A message with an attachment is never queued for a reconnect. Reading a thread lists each attachment's name, type and size; downloading the file itself through the API is not offered yet.

bash
curl -X POST https://api.prospectapis.com/v1/chats \
  -H "Authorization: Bearer $PROSPECTAPIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person_refs": ["<person_ref>", "<person_ref>"], "text": "Hello both", "subject": "Intro"}'

Check and disconnect

GET /v1/accounts/session
{
  "connected": true,
  "status": "active",
  "account": { "handle": "jane-doe", "name": "Jane Doe" },
  "egress": "dedicated",
  "created_at": "2026-10-31T17:02:11Z",
  "updated_at": "2026-10-31T17:02:11Z",
  "last_used_at": null
}

status turns dead when the session signs out on the platform side; connect again to resume. DELETE /v1/accounts/session answers { "deleted": true, "connected": false }, or deleted: false when nothing was connected. It works even at a zero balance.

What we store, and what we delete

The session we store for a connected account is kept encrypted in our database, used only to perform the actions you request, never shown to another customer, and deleted from our database when you disconnect. No route ever returns it, including to you. We log each action (endpoint, time and result) for billing and abuse prevention, and do not store message content in our database. The full wording is in the terms, under Connected accounts.

Connect only an account you own or are authorized to operate. You stay responsible for following that platform's own rules on automated activity, and we may pace or pause an account to protect it, as the acceptable use policy sets out.

Codes

StatusCodeWhat to do
400invalid_requestA missing or unknown field, or a value out of range. The message names it.
409two_factor_requiredSend the same sign-in again with code and challenge_id.
409email_code_requiredThe account emailed a code: enter it at handoff_url, or send it as code with challenge_id.
409captcha_requiredA person must finish a check: open handoff_url before it expires, then send the request again with challenge_id.
410challenge_expiredMore than 15 minutes passed, or the challenge was not issued to your account. Start again.
422session_logged_outThe session you sent is signed out. Sign in again and send a fresh one.
422bad_credentialsThe sign-in details were not accepted.
422account_restrictedThe platform has restricted the account. Only its holder can resolve that; retrying here will not help.
429rate_limitedMore than 10 connect or sign-in attempts in a minute for your account, or too many sign-in attempts for this account on the platform side. Wait a few minutes and retry.
501session_connect_not_available_yetConnecting with a session is switched off on this server. Nothing was stored.
501login_not_available_yetConnecting by signing in is switched off on this server. Nothing was stored.
503temporarily_unavailableConnecting is unavailable right now. Nothing was stored; retry shortly.
503egress_unavailableNo dedicated connection is free for a new account right now. Nothing was stored. Try again shortly, or connect with your own proxy_url.

A write called before any account is connected answers 409 account_not_connected. None of these answers is billed; the full list is on errors.

From an agent

The MCP server has one tool per route: account_connect, account_login, account_status and account_disconnect. A session string and a password are credentials, so pass them only from a client you trust. Our guide to researching prospects with an AI agent covers giving an agent a key safely.

Next: see what a connected account can do on the LinkedIn automation API page, or why connecting is safe to try on connect a LinkedIn account. ProspectAPIs is independent and is not affiliated with or endorsed by LinkedIn. No key yet? Create a free account; connecting is free.

Was this page helpful?