Skip to main content
POST
/
api
/
lists
/
import-sales-nav
Import leads from a Sales Navigator URL
curl --request POST \
  --url https://app.puffle.ai/api/lists/import-sales-nav \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "url": "<string>",
  "listId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "listName": "<string>",
  "maxResults": 4503599627370495,
  "skipExistingCustomers": true
}
'
{ "success": true, "listId": "aaaaaaaa-1111-2222-3333-444444444444", "runId": "run_abc123", "maxResults": 2500, "wasCapped": false }

Overview

Starts a background import of LinkedIn Sales Navigator people search results into a Puffle list. The request is non-blocking — the handler validates inputs, picks a Sales Navigator-enabled LinkedIn account, creates or reuses a list, caps the import at what the caller can afford in credits, enqueues the sales-nav-import Trigger.dev task, and returns the task’s runId. Key behaviours:
  • URL type must be people search. The URL path must contain /people. Company and account URLs are rejected with 400.
  • Sales Navigator required. The caller must have a connected LinkedIn account with has_sales_navigator = true. Check with getSalesNavAccess before calling.
  • List creation is implicit. Omit listId to auto-create a list named Sales Nav Import - mm/dd/yyyy (or pass listName for a custom name).
  • Credit-capped. The request reserves IMPORT_LEAD credits (1 per lead). If the caller’s balance is below the requested maxResults, the import is capped to the affordable quantity and wasCapped: true is returned. A zero balance responds 402.
  • Server-side dedupe. When skipExistingCustomers is true (default), the import task skips leads already present in the user’s other lists.

AI agent notes

Preconditions:
  • Call getSalesNavAccess first. A 400 with No Sales Navigator account found means the user has not connected a Sales Nav LinkedIn account yet.
  • If passing listId, the list must belong to the caller — otherwise 403.
After the call:
  • Poll GET /api/lists/{listId}/rows to observe rows appearing. Typical imports take several minutes for a few thousand leads.
  • The runId corresponds to the Trigger.dev sales-nav-import task. Use the Trigger.dev dashboard or seer skill for deep inspection if the import stalls.
Credit capping:
  • Inspect wasCapped and maxResults in the response. If wasCapped: true, warn the human that the import was shortened; propose a credit top-up before re-running.
Idempotency:
  • Not idempotent — each call enqueues a new task run. Avoid re-issuing the request on network retry; instead, surface the original runId to the user.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Body

application/json

Kick off a Sales Navigator import. The caller must have at least one connected LinkedIn account with Sales Navigator premium — check first via getSalesNavAccess.

url
string<uri>
required

LinkedIn Sales Navigator people search URL. The path must contain /people — lead/company search URLs are rejected with 400.

listId
string<uuid>

Existing list to append into. If omitted, a new list is created on the fly using listName (or a default timestamped name).

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
listName
string

Name for the new list when listId is omitted. Defaults to Sales Nav Import - <mm/dd/yyyy>.

maxResults
integer

Upper bound on leads to import. Defaults to 2500. The server additionally caps this to what the caller can afford in credits (1 credit per lead via IMPORT_LEAD); the effective cap is returned in the response as maxResults.

Required range: 0 < x <= 9007199254740991
skipExistingCustomers
boolean

When true (default), leads already present in the user's other lists are skipped server-side during the import task.

Response

Import accepted and scheduled on Trigger.dev. Leads will populate into the list asynchronously.

success
enum<boolean>
required
Available options:
true
listId
string<uuid>
required

The list being imported into — either the provided listId or the freshly created list.

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
runId
string
required

Trigger.dev run id for the sales-nav-import task. Poll it via the Trigger.dev dashboard or look for rows appearing under GET /api/lists/{id}/rows.

maxResults
integer
required

Effective cap applied to the import after credit-based adjustment. May be lower than the requested maxResults if the user's credit balance couldn't cover the full request.

Required range: -9007199254740991 <= x <= 9007199254740991
wasCapped
boolean
required

True when the effective maxResults was reduced below the requested value because the user didn't have enough credits for the full import.