auth.intent
Authenticate a LinkedIn account with credentials or a session cookie.
Prerequisites
- A Curviate API key, passed as
apiKeywhen you construct the client. Quickstart shows how to create one.
Signature
intent(body: AuthIntentBody): Promise<AuthIntentResult>Example
import { Curviate } from "@curviate/sdk";
const curviate = new Curviate({
apiKey: "cvt_live_...",
baseUrl: "https://api.curviate.com",
});
const result = await curviate.auth.intent({
seat_id: "YOUR_SEAT_ID",
auth_method: "credentials",
credentials: { email: "YOUR_EMAIL", password: "YOUR_PASSWORD" },
country: "US",
});
console.log(result.account_id);Parameters
| Name | Type | Required | Description |
|---|---|---|---|
seat_id | string | No | The empty seat this NEW account will occupy. Required on a new connect; omit it and the call returns 400 INVALID_REQUEST with 'seat_id is required'. Seat ids look like seat_01H..., and every seat you own is listed by GET /v1/accounts/seats (any item with occupied false is free to use) and with click-to-copy in the seat table on your dashboard. Ignored when account_id is present, because a reconnect keeps the account on its current seat. |
auth_method | string | Yes | How to authenticate. 'credentials' reads the nested credentials object (email + password). 'cookie' reads the nested cookie object (li_at) and also requires a top-level user_agent. Neither set of fields is accepted at the top level. |
credentials | object | No | Email + password authentication, supplied as a NESTED object (email and password do not go at the top level). Required when auth_method=credentials. |
cookie | object | No | Session-cookie authentication, supplied as a NESTED object (li_at does not go at the top level). Required when auth_method=cookie, which also requires a top-level user_agent. |
account_id | string | No | Present = re-authenticate this existing account in place (reconnect); omit = connect a new account. |
linkedin_premium | string | No | Optional. Which LinkedIn premium surface this connection should ask for: 'sales_navigator' or 'recruiter'. Omit it and the connection asks for every product, and LinkedIn activates whichever ones the account actually has. One LinkedIn account can hold only one of the two premium surfaces, and when both are asked for Sales Navigator takes precedence, so set this to 'recruiter' if the account holds both and you want the Recruiter surface. This applies per connection and is not remembered: state it on every connect and reconnect where Recruiter must win. |
timezone | string | No | Optional IANA zone name for this account's LinkedIn session, e.g. Europe/Berlin. Sent in canonical form; a UTC offset such as +02:00 is a 400. |
external_id | string | No | Your own id for the end user who owns this account, 1-255 chars, not unique. Treat it as opaque; avoid emails. |
products | array | No | Optional allow-list of premium products to ask for: sales_navigator, recruiter. Omit to ask for both; [] asks for none. Classic LinkedIn and company pages are always included. |
country | string | No | Where LinkedIn sees this account connecting from: a supported ISO 3166-1 alpha-2 country code (e.g. US, DE; case-insensitive). Pick the country the account owner normally signs in from. A new connect needs exactly one of country, ip or proxy. Strict by default: the connect fails rather than use another country, unless allow_country_fallback is true. |
ip | string | No | A public IPv4 address; its country becomes the connection location (strict by default). An alternative to country: send exactly one of country, ip or proxy on a new connect. |
allow_country_fallback | boolean | No | Optional. false (the default with country or ip): only ever connect from that country; a connect fails when no connection is free there. true: a connection from another country may be used when none is free in the chosen one. Not accepted with proxy. |
proxy | object | No | Your own proxy for this account's traffic. The proxy decides where LinkedIn sees the account connecting from, so country, ip and allow_country_fallback are not accepted with it. |
user_agent | string | No | Exact browser User-Agent to pin for this account. REQUIRED for a cookie connect: send the User-Agent of the browser the li_at cookie was copied from. Optional for a credentials connect, where it helps an account that hits disconnection issues. |
sync_limit | object | No | Optional caps on how much history is synced for this account. |
recruiter_contract_id | string | No | Which Recruiter contract to bind this account to. Only meaningful when the LinkedIn account holds a Recruiter subscription. |
Returns
Resolves to AuthIntentResult. Top-level fields: object, account_id, status, external_id, owner_user_id, team_access, connection_location, safety_warning.
Error codes
| Code | What it means, and what to do |
|---|---|
UNAUTHORIZED | The API key is missing, malformed, or revoked. Check the key you passed to the client. |
INVALID_REQUEST | A parameter failed validation. The message names the offending field; fix the request rather than retrying it. |
RATE_LIMIT_ACCOUNT | This account's own quota is exhausted. Wait for the window in the Retry-After header, then retry. |
RATE_LIMIT_TENANT | The tenant-wide quota is exhausted across all accounts. Slow the whole workload, not just this call. |
PLATFORM_RATE_LIMIT | LinkedIn is throttling this account. Back off well beyond the hinted delay; sustained pressure risks the account. |
PLATFORM_ERROR | An upstream failure, usually transient: retry once with backoff before treating it as a real error. Check the response first, though. When it carries retry_likely_to_succeed: false and retry_hint: {kind: "never"}, retrying cannot help and backing off only delays the real answer. |
ACCOUNT_ALREADY_LINKED | That LinkedIn account is already connected. Reconnect or adopt the existing account instead of linking it again. |
CHECKPOINT_ALREADY_RESOLVED | The challenge is already solved. Poll for the account's status instead. |
CHECKPOINT_EXPIRED | The challenge timed out. Request a fresh one and solve it promptly. |
CHECKPOINT_INVALID_CODE | The code was wrong. Ask the account owner for the current one and resubmit. |
CHECKPOINT_MAX_ATTEMPTS | Too many wrong codes. Restart the connect flow from the beginning. |
CHECKPOINT_NOT_FOUND | No challenge is pending for that account. Start the connect flow again. |
CHECKPOINT_UNSUPPORTED | This challenge type cannot be solved through the API. Sign in on LinkedIn directly first. |
CONNECTION_IN_PROGRESS | A connection attempt for this LinkedIn account is already open. Wait for it to finish or expire before starting another. |
CONNECTION_LOCATION_REQUIRED | No connection location was named. Send exactly one of country, ip or your own proxy (on PATCH, proxy: null needs a country). |
CONNECTION_LOCATION_UNAVAILABLE | No connection is free in that country right now, or the change landed elsewhere. Try a nearby country or allow fallback; read connectionLocation for where the account connects from now. |
INTERNAL | An unexpected server error. Retry once; if it persists, it is ours, not yours. |
LINKEDIN_AUTH_FAILED | LinkedIn rejected the credentials. Confirm them with the account owner. |
LINKEDIN_COOKIE_INVALID | The session cookie is expired or invalid. Supply a fresh one, or connect with credentials. |
LINKEDIN_RATE_LIMITED | LinkedIn is rate limiting the sign-in itself. Wait substantially longer before retrying. |
LINKEDIN_SERVICE_UNAVAILABLE | LinkedIn is unavailable, or the resource is still being prepared upstream. Retry with backoff. |
NO_ACTIVE_SEAT | The targeted account is not on an active seat. Buy or attach a seat in Billing, then retry. |
PAYLOAD_TOO_LARGE | Three limits can trigger this. The platform's own ceiling on total request size is the lowest and the one you are most likely to hit: it starts rejecting at roughly 1 MB, so a handful of photo-sized images is refused even though it clears everything below. Above that, this API caps one attachment at 5 MiB of file content and the whole request body at 9 MiB. Attachments travel base64-encoded, which inflates them by about a third, so a 5 MiB file costs roughly 6.7 MiB of the body budget. Send fewer or smaller attachments; retrying unchanged will not help. |
PAYMENT_REQUIRED | The workspace has no active subscription, or its subscription is past due. Subscribe, or update the payment method, then retry. |
REAUTH_REQUIRED | A cookie replay cannot change an account's scope. Re-authenticate with credentials instead. |
Every code above is a stable CurviateError.code you can branch on. The full list, the response envelope, and retry semantics are in the Error codes reference.
Next steps
- Quickstart: connect a LinkedIn account. An empty account list means the key works and nothing is connected yet.
auth.getSession: Poll a credential connect session by its account id, a pure status read that makes no external call and does not itself complete the connection.auth.pollCheckpoint: Poll for mobile-app approval of a pending checkpoint challenge until it leaves pending.- SDK Quick Start: installation, the client, account scoping, and pagination.