Skip to main content
GET
/
api
/
dashboard
/
leads
List leads across all lists
curl --request GET \
  --url https://app.puffle.ai/api/dashboard/leads \
  --header 'Authorization: Bearer <token>'
{
  "rows": [
    {
      "id": "p1111111-1111-1111-1111-111111111111",
      "list_id": "l1111111-1111-1111-1111-111111111111",
      "linkedin_url": "https://linkedin.com/in/jane",
      "profile_data": {
        "fullName": "Jane Doe",
        "currentCompany": "Acme",
        "currentRole": "VP of Sales"
      },
      "source": "leads_search",
      "added_at": "2026-04-21T09:00:00Z",
      "company_row_id": "c1111111-1111-1111-1111-111111111111",
      "company_domain": "acme.com",
      "lists": [
        {
          "id": "l1111111-1111-1111-1111-111111111111",
          "name": "Q2 SaaS VPs"
        },
        {
          "id": "l2222222-1111-1111-1111-111111111111",
          "name": "Austin Pilot"
        }
      ]
    }
  ],
  "total": 1337,
  "hasMore": true
}

Overview

Returns a deduplicated view of every person or company across all lists the caller owns. Intended to power the dashboard’s “All Leads” and “All Companies” tabs. People deduplication cascades on name + company + linkedin_url — a single person appearing across three lists returns once, with a lists array listing all three. Company deduplication cascades on domain (falling back to name). Each company row includes employeesInLists, the count of unique people from that company across any of the caller’s lists (deduped by LinkedIn URL). Pagination is applied after deduplication so total is the true deduplicated count. Search hits the indexed search_text column; PostgREST special chars are stripped server-side to prevent injection.

AI agent notes

When to use:
  • Building a cross-list summary (“how many unique VPs of Sales do I have across my lists?”)
  • Answering dedup questions before a campaign (“is this prospect already in another list?”)
  • Exporting a flat book-of-business view
When NOT to use: if you only care about one list, hit GET /api/lists/{id}/rows — it is simpler and does not incur the dedup cost.Pagination:
  • limit defaults to 500, hard cap is 10,000. Most callers want one big fetch and client-side filtering.
  • offset is applied after dedup — offset=500&limit=500 is safe.
  • hasMore tells you when to stop.
Performance caveats:
  • Dedup fetches up to 10,000 raw rows per request before deduplicating — for users with huge lists the endpoint may get tight on the default serverless timeout. If you see a 500, retry with a smaller limit and page client-side.
  • Safe to call frequently (pure read), but respect the global 100 req per minute rate limit.
See also: Lists · Start a lead search · Agent Playbook.

Authorizations

Authorization
string
header
required

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

Query Parameters

type
enum<string>

Which entity to return. Defaults to people. Companies are deduplicated by domain and include an employeesInLists count summarising how many unique people from the same company appear across the caller's lists.

Available options:
people,
companies
limit
integer

Page size. Defaults to 500, hard-capped at 10,000 (intentional — the dashboard fetches in one shot and paginates client-side).

Required range: 0 < x <= 10000
offset
integer

Offset applied after deduplication — so total row counts remain accurate across pages.

Required range: 0 <= x <= 9007199254740991

Case-insensitive search against the indexed search_text column. PostgREST special characters (,, (, ), %, _, \) are stripped server-side for safety.

Response

Deduplicated rows + total + pagination cursor.

Unified dashboard view across all lists.

rows
object[]
required

Shape depends on type; every row in a single response shares the same shape.

Person row — returned when type === "people".

total
integer
required

Total deduplicated rows across all the caller's lists.

Required range: 0 <= x <= 9007199254740991
hasMore
boolean
required

True when offset + limit < total.