Skip to main content
POST
/
api
/
leads
/
search
Start Lead Search
curl --request POST \
  --url https://app.puffle.ai/api/leads/search \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "prompt": "<string>",
  "fetch_count": 1250,
  "listId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "listName": "<string>"
}
'
{
  "task": {
    "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "type": "lead_search",
    "status": "<string>",
    "statusUrl": "<string>",
    "resultListId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "prompt": "<string>",
    "title": "<string>",
    "filters": {},
    "resultCount": 4503599627370495,
    "errorMessage": "<string>",
    "createdAt": "2023-11-07T05:31:56Z",
    "completedAt": "2023-11-07T05:31:56Z"
  },
  "list": {
    "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "name": "<string>"
  }
}
CLI:
puffle lead search create --prompt <prompt> --fetch-count <fetch-count>
puffle lead search create --prompt <prompt> --fetch-count <fetch-count> --list-id <list-id> --list-name <list-name>

Overview

Creates a Search from prompt plus fetch_count, guarantees a result List, and dispatches the lead-search Trigger.dev task. Repeating the same prompt for the same List continues from the stored search cursor, so the next run returns the next batch instead of the same people again. The flow is asynchronous: the response returns a task plus list. Poll GET /api/leads/search?taskId={taskId} until the search is terminal, then open the returned List or read raw rows with GET /api/leads/search/results?taskId={taskId}. Fetches up to 2500 new rows per run (the server clamps fetch_count to that ceiling). Billing happens only for records actually saved.

Binding to a list

Supplying listId binds the search to an existing List when the caller owns it. If that id does not exist, the route creates a List with that client-generated id. Omitting listId creates a new result List named from listName or the prompt. Only one active search task per List; a second concurrent POST returns 409.
This operation shares the URL path /api/leads/search with the read verb. See Get search task to enumerate the caller’s recent searches.
See also: Get search task · Get results · AI agent playbook.

AI agent notes

The lead-discovery journey:
  1. Ask the human for a natural-language prompt and a fetch_count.
  2. POST /api/leads/search with { prompt, fetch_count }. Include listId only when you want to populate an existing or client-generated List id.
  3. GET /api/leads/search?taskId={taskId} — poll every 5 to 10 s until status === "completed".
  4. Use the response list.id as the populated result List. Optionally call GET /api/leads/search/results?taskId={taskId} to inspect raw result rows.
  5. To get more people for the same audience, call POST /api/leads/search again with the same prompt and the same listId.
Pre-flight checks:
  • fetch_count is clamped at 2500 — do not bother asking for more.
  • Repeating the same normalized prompt continues pagination. Changing the wording creates a new search.
  • Lead Search currently returns people. Company details come from the returned person’s current company fields.
Polling cadence: every 5 to 10 s while status is pending or running. Most runs finish within 2 minutes; give up at 10 minutes and escalate with the correlationId.On 409: another search is active for the list. Wait for it to complete, or DELETE it first.

Authorizations

Authorization
string
header
required

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

Body

application/json

Natural-language lead search request.

prompt
string
required

Natural-language description of the leads to find.

Required string length: 1 - 2000
fetch_count
integer
required

Number of new leads to fetch for this run.

Required range: 0 < x <= 2500
listId
string<uuid>

Optional list to auto-populate when the search completes.

listName
string

Optional name for the result list. Used when listId is omitted or points to a new client-generated list id.

Required string length: 1 - 120

Response

Existing same-prompt search task continued or already exhausted.

task
object
required

Canonical lead search task.

list
object
required

List that receives this search's results.