> ## Documentation Index
> Fetch the complete documentation index at: https://docs.linkupapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect Account

> Connect a channel account to start using the API

Connect a new channel account (LinkedIn, WhatsApp, etc.) to your API key. Once connected, you receive an `account_id` to use in all subsequent requests.

<Note>
  This endpoint costs **1 credit** per request. Ignore this if you're on per-seat pricing: usage is unlimited.
</Note>

### Header Parameters

<ParamField header="x-api-key" type="string" required>
  Your API key
</ParamField>

### Body Parameters

<ParamField body="platform" type="string" required>
  The channel platform to connect. Available: `linkedin`, `whatsapp`, `email`. Optional in the one case below where you pass an existing `account_id` to activate a premium seat — the account already carries its platform. For `email`, see [Email mailbox](#email-mailbox) below.
</ParamField>

<ParamField body="email" type="string">
  Account email address (required for credential-based login)
</ParamField>

<ParamField body="password" type="string">
  Account password (required for credential-based login)
</ParamField>

<ParamField body="login_token" type="string">
  Authentication token/cookie for direct token-based connection. Alternative to email+password.
</ParamField>

<ParamField body="phone_number" type="string">
  WhatsApp only. The number to link, e.g. `+33612345678`. Sets the proxy country when `country` is not given.
</ParamField>

<ParamField body="country" type="string" default="FR">
  Country code for proxy selection. Available: US, UK, FR, DE, NL, IT, IL, CA, BR, ES, IN
</ParamField>

<ParamField body="account_name" type="string">
  Optional display name for the account. Defaults to the email address.
</ParamField>

<ParamField body="challenge_type" type="string" default="code_challenge">
  Type of 2FA challenge to use if the account has two-factor authentication enabled.

  * `code_challenge` — receive a verification code via email, SMS, or authenticator app. You must then submit the code via `/v2/checkpoint`.
  * `app_challenge` — confirm the login directly from the platform's mobile app. No code needed — just call `/v2/checkpoint` with the `account_id` after approving on the app.

  This is a preference, LinkedIn may impose another method: check `checkpoint_type` in the response.
</ParamField>

<ParamField body="sales_nav" type="boolean" default={false}>
  Also activate the account's **Sales Nav** seat during login (requires the account to hold a Sales Nav license). No extra credential is needed — the seat is derived from the existing session. See [Sales Nav](#sales-nav) below.
</ParamField>

<ParamField body="account_id" type="string">
  Pass an **existing** account's id together with `sales_nav: true` to activate a Sales Nav seat on an already-connected account (e.g. bought after connecting) — no re-login, no credential, and **no credit**. When set, no other login parameter is required.
</ParamField>

<ParamField body="proxy" type="string | object">
  LinkedIn only. Your own HTTP(S) proxy for this account — the login and every later request go through it. See [Custom proxy](#custom-proxy) below.
</ParamField>

### Response

<ResponseField name="success" type="boolean">
  Whether the request was successful
</ResponseField>

<ResponseField name="data" type="object">
  <Expandable title="Properties">
    <ResponseField name="account_id" type="string">
      The unique identifier for the connected account. Use this in all future requests.
    </ResponseField>

    <ResponseField name="platform" type="string">
      The platform that was connected
    </ResponseField>

    <ResponseField name="status" type="string">
      Account status: `connected` (ready to use) or `checkpoint_required` (needs 2FA verification)
    </ResponseField>

    <ResponseField name="message" type="string">
      Additional information (present when checkpoint is required)
    </ResponseField>

    <ResponseField name="checkpoint_type" type="string">
      Where the code went, when `checkpoint_required`: `email`, `sms`, `authenticator_app`, `app_approval` or `code`.
    </ResponseField>

    <ResponseField name="sent_to" type="string">
      Masked destination when LinkedIn shows it, e.g. `phone number ending with 23`.
    </ResponseField>

    <ResponseField name="sales_nav" type="object">
      Present when `sales_nav: true` was requested. `{ "connected": true, "contract_id": "...", "seat_id": "..." }` on success, or `{ "connected": false, "error": "..." }` if no seat could be activated. When the login returns `checkpoint_required`, this is `{ "pending": true }` and the seat is activated once the checkpoint completes.
    </ResponseField>

    <ResponseField name="proxy" type="object">
      Present when `proxy` was given: `{ "mode": "custom", "host": "...", "port": 8080 }`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json Connected Successfully theme={null}
  {
    "success": true,
    "data": {
      "account_id": "69c127c37cae0494dd827286",
      "platform": "linkedin",
      "status": "connected"
    },
    "metadata": {
      "action": "login",
      "credits_consumed": 1,
      "timestamp": "2025-01-15T10:30:00.000000"
    }
  }
  ```

  ```json Checkpoint Required (2FA) theme={null}
  {
    "success": true,
    "data": {
      "account_id": "69c127c37cae0494dd827286",
      "platform": "linkedin",
      "status": "checkpoint_required",
      "message": "Check your email for verification code",
      "checkpoint_type": "sms",
      "sent_to": "phone number ending with 23"
    },
    "metadata": {
      "action": "login",
      "credits_consumed": 1,
      "timestamp": "2025-01-15T10:30:00.000000"
    }
  }
  ```

  ```json Checkpoint Required (WhatsApp) theme={null}
  {
    "success": true,
    "data": {
      "account_id": "6ab7dd7ba4886df610eab269",
      "platform": "whatsapp",
      "status": "checkpoint_required",
      "checkpoint_type": "whatsapp_qr",
      "qr_code": "https://wa.me/settings/linked_devices#2@…",
      "qr_code_image": "data:image/png;base64,iVBORw0KGgo…",
      "expires_in_seconds": 180
    },
    "metadata": {
      "action": "login",
      "credits_consumed": 0,
      "timestamp": "2026-09-26T15:00:00.000000"
    }
  }
  ```

  ```json Error Response theme={null}
  {
    "success": false,
    "error": {
      "code": "CHANNEL_ERROR",
      "message": "Bad username or password"
    },
    "metadata": {
      "action": "login",
      "credits_consumed": 0,
      "timestamp": "2025-01-15T10:30:00.000000"
    }
  }
  ```
</ResponseExample>

### Login Methods

There are two ways to connect an account:

1. **Credential-based login** — provide `email` + `password`. If 2FA is enabled, you'll receive a `checkpoint_required` status and need to call `/v2/checkpoint`.

2. **Token-based login** — provide a `login_token` directly. No 2FA step needed.

### Email mailbox

Connect a mailbox with `platform: "email"` and a `provider`:

* `gmail_oauth` / `m365_oauth` — OAuth. Two steps: this call returns `status: "checkpoint_required"` + an `authorization_url`; redirect the user there, then submit the returned `code` to [`/v2/checkpoint`](/api-reference/v2/accounts/checkpoint). By default LinkupAPI's own OAuth app is used — pass `oauth_client_id` + `oauth_client_secret` in `params` to use your own.
* `smtp_generic` — IMAP/SMTP. Verified and connected in one call (no checkpoint).

The mailbox address is the top-level **`email`** field (the same one used for credential login), and its display name the top-level **`account_name`**. Everything else goes in `params`: optional `daily_limit` (default 40); `redirect_uri` for OAuth; `smtp` `{ host, port, password }` (+ optional `imap` `{ host, port }`) for SMTP. Tip: call [`/v2/email/autoconfig`](/api-reference/v2/email/autoconfig) first to get the right `provider` and server settings. Connecting a mailbox is **free**.

```json OAuth (step 1) theme={null}
{
  "platform": "email",
  "provider": "gmail_oauth",
  "email": "you@company.com",
  "params": { "redirect_uri": "https://yourapp.com/oauth/email/callback" }
}
```

```json SMTP (one call) theme={null}
{
  "platform": "email",
  "provider": "smtp_generic",
  "email": "you@company.com",
  "params": {
    "smtp": { "host": "smtp.company.com", "port": 587, "password": "app-password" },
    "imap": { "host": "imap.company.com", "port": 993 }
  }
}
```

Common failures return the standard error envelope: an address with no Gmail mailbox or a rejected SMTP login → `CHANNEL_ERROR` (422); an expired/reused code → `INVALID_PARAMS` (400); denied consent → `FORBIDDEN` (403). A failed attempt leaves no leftover account.

### WhatsApp

1. `platform: "whatsapp"` + `phone_number` → `checkpoint_required` with a QR code (`qr_code_image`)
2. Scan it on the phone: WhatsApp › Settings › Linked devices › Link a device
3. Poll [`/v2/checkpoint`](/api-reference/v2/accounts/checkpoint) with the `account_id` every few seconds → current QR, then `connected`

* The QR refreshes every \~20 s and expires after 3 min: `/v2/checkpoint` with `resend: true` gives a new one
* Can't scan (QR shown on the same phone)? Pass `params.pairing_code: true`: you get an 8-character `pairing_code` to type on the phone instead (Link a device › Link with phone number instead)
* Free

```json WhatsApp theme={null}
{ "platform": "whatsapp", "phone_number": "+33612345678" }
```

### Sales Nav

The Sales Nav seat is derived from the account's existing session — there is **no separate login**. There are two ways to activate it:

1. **At login** — pass `sales_nav: true` alongside your credentials or `login_token`. The seat is activated in the same request.
2. **On an already-connected account** — pass `account_id` + `sales_nav: true` (no credential, no credit). Ideal when the user buys Sales Nav after connecting.

The seat is attached to the account and renewed automatically when it expires. Activating a seat never breaks an otherwise-successful login: if the account has no Sales Nav license, you still get `status: connected` with `sales_nav.connected: false`.

<ResponseExample>
  ```json Connected + Sales Nav theme={null}
  {
    "success": true,
    "data": {
      "account_id": "69c127c37cae0494dd827286",
      "platform": "linkedin",
      "status": "connected",
      "sales_nav": {
        "connected": true,
        "contract_id": "2016220713",
        "seat_id": "1545550052"
      }
    },
    "metadata": {
      "action": "login",
      "credits_consumed": 1,
      "timestamp": "2025-01-15T10:30:00.000000"
    }
  }
  ```

  ```json Activate seat on existing account (account_id) theme={null}
  {
    "success": true,
    "data": {
      "account_id": "69c127c37cae0494dd827286",
      "platform": "linkedin",
      "status": "connected",
      "sales_nav": { "connected": true, "contract_id": "2016220713", "seat_id": "1545550052" }
    },
    "metadata": {
      "action": "login",
      "credits_consumed": 0,
      "timestamp": "2025-01-15T10:30:00.000000"
    }
  }
  ```
</ResponseExample>

### Custom proxy

* `proxy`: `http://user:pass@host:port`, `host:port:user:pass`, `host:port`, or `{ "host", "port", "username", "password" }`. HTTP(S) only
* tested before the login — unreachable proxy returns `400`, no credit
* kept for later re-logins. Change it with [Set Custom Proxy](/api-reference/v2/accounts/set-proxy), remove it with [Remove Custom Proxy](/api-reference/v2/accounts/remove-proxy)

### Notes

* The `account_id` returned is permanent — store it and reuse it for all API calls
* If you receive `checkpoint_required`, use the `/v2/checkpoint` endpoint to complete verification
* The `country` parameter determines which proxy is used for the connection
