Account
The account commands manage LinkedIn account connections — linking new accounts, resolving the verification checkpoints LinkedIn issues during sign-in, and managing already-connected accounts. All account commands are root-scoped: they operate on your workspace and do not require --account.
Changed in 0.15.0:
account connect-link,account reconnect-link, andaccount reconnectare removed — the hosted-link flow and the in-place re-authorization flow have no v2 endpoint.account linknow only ever connects a new LinkedIn account into an empty seat; it does not take an existingaccount_id. There is currently no CLI command to re-authorize an already-connected, disconnected account in place — see the note under Checkpoint flow below.account connect-session pollis retained, but its--sessionvalue changed meaning: it is now theaccount_idreturned byaccount link's checkpoint response (a plain status poll), not a separate hosted-link session id.
account list and get
# List all connected accounts (paginated)
curviate account list [--limit <n>] [--cursor <token>] [--all] [--max-pages <n>]# Get a single account by ID (verbatim account ID, not a LinkedIn identifier)
curviate account get <account_id>account get returns the account's current status, its quotas (one entry per tracked quota family, with remaining/total/recommended_throttle_hint), and — with --verbose — the cached enrichment fields (username, premium_id, public_identifier, signatures, groups). Those five enrichment fields are best-effort: for accounts connected going forward they may be null / empty, so treat them as optional. full_name and substrate_created_at remain populated.
Account status is one of active, reconnect_needed, restricted, connecting, or disconnected.
account link
Connect a new LinkedIn account into an empty seat. Requires --seat-id and --auth-method.
# Link a new LinkedIn account (write)
curviate account link \
--seat-id <seat_id> \
--auth-method <credentials|cookie> \
[--email <email>] \
[--password <password>] \
[--password-stdin] \
[--li-at <cookie>] \
[--li-at-stdin] \
[--li-a <cookie>] \
[--user-agent <ua>] \
[--country <code>] \
[--ip <address>] \
[--proxy-protocol <http|https|socks5>] \
[--proxy-host <host>] \
[--proxy-port <port>] \
[--proxy-username <user>] \
[--proxy-password <pass>] \
[--recruiter-contract-id <id>] \
[--no-interactive]Cookie auth requires --user-agent. When --auth-method cookie, pass the exact browser User-Agent the li_at cookie was captured with — cookie sessions are pinned to it. Omitting --user-agent on a cookie link fails with INVALID_REQUEST. --user-agent stays optional for credentials auth.
Prefer --password-stdin / --li-at-stdin (or the CURVIATE_LINKEDIN_PASSWORD / CURVIATE_LINKEDIN_LI_AT environment variables) over passing a secret on the command line, where it is visible to other processes and saved in shell history.
On success the command prints the connected account:
{ "object": "account", "account_id": "acc_...", "status": "active" }If LinkedIn issues a verification challenge, the response is a checkpoint instead of an account:
{
"object": "checkpoint",
"status": "checkpoint_required",
"account_id": "acc_...",
"challenge_type": "two_factor_app",
"expires_at": "2026-06-08T10:10:00Z"
}On an interactive terminal, account link then guides you through the checkpoint in-process — prompting for the code, or waiting out a mobile-app approval — and exits once the account connects. Pass --no-interactive to always render the checkpoint envelope and exit instead of prompting, even on a TTY. On a non-interactive session it prints the checkpoint envelope and exits with the "auth needed" code so a script can resolve it later with the checkpoint commands below. The account_id in the checkpoint is the handle you pass to those commands.
If the account is already connected, account link returns ACCOUNT_ALREADY_LINKED (a LinkedIn identity maps to one account per workspace). When your workspace already owns that account, the error names your own account_id. A checkpoint resolution that turns out to re-adopt an identity your workspace already holds returns the account with "recovered": true.
account connect-session poll
Poll the status of an in-progress connect — a pure status read that makes no external call and does not itself resolve a checkpoint. --session takes the account_id from account link's checkpoint (202) response — not a separately-minted session id.
# Single poll (prints the session status, exits 0 regardless of status)
curviate account connect-session poll --session <account_id>
# Block until the session resolves (or the wait window elapses)
curviate account connect-session poll --session <account_id> --wait [--timeout <ms>]status is checkpoint_required, done, expired, or failed; account_id is populated only once status is done. Use this as a lightweight way to check on a link attempt without solving the checkpoint yourself — to actually resolve a pending checkpoint, use the checkpoint commands below.
account update and disconnect
# Update an account's metadata / proxy configuration (write, --preview accepted)
curviate account update <account_id> \
[--metadata <json>] \
[--proxy-protocol <http|https|socks5>] \
[--proxy-host <host>] \
[--proxy-port <port>] \
[--proxy-username <user>] \
[--proxy-password <pass>] \
[--clear-proxy]--metadata sets a flat key/value map of your own tags on the account and replaces the stored map wholesale (keys you omit are removed); pass it as a JSON object, e.g. --metadata '{"team":"growth","region":"eu"}'. The --proxy-* flags set a custom proxy; --clear-proxy removes a custom proxy and reverts to automatic proxy protection (mutually exclusive with --proxy-host). A managed location is set only at connect time (on account link) — account update does not accept --country / --ip.
# Permanently disconnect an account (write, --preview accepted)
curviate account disconnect <account_id>Checkpoint flow
When account link returns a checkpoint_required status, LinkedIn is waiting for a verification code or a mobile-app approval. The checkpoint commands are account-scoped — pass the account_id from the 202 response as a positional argument:
# Solve a code-based checkpoint (OTP / 2FA) (write)
curviate account checkpoint solve <account_id> --code <code># Re-request the verification notification (e.g. the user never got the code) (write)
curviate account checkpoint request <account_id># Poll a mobile-app-approval checkpoint (write)
curviate account checkpoint poll <account_id> [--wait] [--timeout <ms>]solvesubmits a code and, on success, returns the connectedaccount. A chained challenge (for example OTP then 2FA) returns anothercheckpoint_required— solve the next code at the same account. A wrong code returnsCHECKPOINT_INVALID_CODE.requestre-issues the challenge notification. Itsresentfield is honest:resent: falsemeans there was nothing to re-send (for example atwo_factor_appcode is generated on the device), not a failure. It does not extend the checkpoint's expiry.pollis formobile_app_approvalcheckpoints, where the user approves the sign-in on their phone. While pending it returns{ "object": "checkpoint", "status": "pending", "expires_at": "..." }; once approved it returns the connectedaccount. Add--waitto block until it resolves. A code-based checkpoint returns422here — usesolveinstead.
The mobile-approval window is short (a few minutes — poll until the returned expires_at). If it elapses before the user approves, the checkpoint reaches a terminal expired state with a recovery_hint explaining the next step:
{
"object": "checkpoint",
"status": "expired",
"challenge_type": "mobile_app_approval",
"recovery_hint": "This sign-in wasn't completed in time. If you approved it in the LinkedIn app, this identity may already be connected — try reconnecting, sign in with the cookie method, or check your connected accounts."
}Reconnecting a disconnected account. As of 0.15.0 the CLI does not expose an in-place re-authorization command for an account whose
statusisreconnect_neededordisconnected—account reconnectwas removed, andaccount linkonly opens a brand-new connection into an empty seat. If a previously-connected LinkedIn identity needs fresh credentials, disconnect the stale account and link it again; a checkpoint resolution that re-adopts the same identity returns"recovered": true.
Challenge types
The challenge_type on a 202 checkpoint is one of otp, two_factor_sms, two_factor_app, two_factor_whatsapp, mobile_app_approval, otp_or_mobile_app_approval (the user may either enter a code or approve in the app), or contract_selection (a Recruiter / Sales Navigator seat picker — the response also carries contracts with { id, name } entries; solve with the chosen id). Two challenges cannot be resolved automatically — a CAPTCHA and a phone-number registration; those return 422 with a machine-readable challenge_type of captcha or phone_register.
Examples
List connected accounts
curviate account listLink an account with credentials
curviate account link \
--seat-id seat_abc123 \
--auth-method credentials \
--email user@example.com \
--password-stdin <<< "$LINKEDIN_PASSWORD"Link an account with a cookie
# Cookie auth requires --user-agent (the browser the li_at was captured with)
curviate account link \
--seat-id seat_abc123 \
--auth-method cookie \
--li-at-stdin <<< "$LI_AT" \
--user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"Complete an OTP checkpoint manually
# 1. A non-interactive link returns a checkpoint and the account_id to resolve it
curviate account link --seat-id seat_abc123 --auth-method credentials \
--email user@example.com --password-stdin <<< "$LINKEDIN_PASSWORD" --no-interactive
# => { "object": "checkpoint", "status": "checkpoint_required", "account_id": "acc_X", "challenge_type": "otp", "expires_at": "..." }
# 2. Solve the code from the user's email or authenticator app
curviate account checkpoint solve acc_X --code 123456
# => { "object": "account", "account_id": "acc_X", "status": "active" }
# 3. If the user never received the code, re-request the notification
curviate account checkpoint request acc_XWait out a mobile-app-approval checkpoint
# The user approves the sign-in on their phone; --wait blocks until it resolves
curviate account checkpoint poll acc_X --waitPoll a link attempt's status without solving it
curviate account connect-session poll --session acc_X --waitPreview a disconnect
# See what would be sent without actually disconnecting
curviate account disconnect acc_YOUR_ACCOUNT_ID --preview