Leads Database

Search a global B2B database of people and companies, enrich profiles, and feed the results into your lists and campaigns.

The Leads Database is a prospecting search over a global B2B database of people and companies. It runs entirely on the Swarmhit side: you do not need a connected LinkedIn account to use it, and no LinkedIn action limits apply. Use it to build lead lists from scratch, then hand the results to a campaign for outreach.

Two things shape how you should use it:

Every search result returned and every enrichment that finds a match consumes workspace credits (see Credits and errors). Keep pages small and filters tight. Results are transient: nothing you find is stored in your workspace until you add the person to a list or campaign.

Endpoints

Searching people

searchPeopleDatabase takes a filters object, an optional limit (1 to 100, default 25), and an optional cursor. At least one filter with a value is required (excludeExisting alone does not count), and unknown filter keys are rejected with a 400. Array filters match any of their values and use at most 25 values each (extra values are ignored); text filters are fuzzy. Numeric and boolean filters must be JSON numbers and booleans: a string such as "50" or "true" is ignored.

curl -X POST https://app.swarmhit.com/api/v1/database/people/search \
  -H "Authorization: Bearer swh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "filters": {
      "titles": ["CTO", "VP Engineering"],
      "countries": ["United States"],
      "headcountRanges": ["51-200", "201-500"]
    },
    "limit": 25
  }'

People filters

FilterTypeMatches
titles / excludeTitles / pastTitlesstring[]Current job titles (fuzzy), title words to exclude, past titles (fuzzy)
seniorities, departments, functionsstring[]Seniority levels, departments, job functions (use suggestions for valid values)
keywordsstring or string[]Headline keywords (fuzzy, ANY of the array)
keywordInProfilestring or string[]Profile summary/bio keywords (fuzzy, ANY of the array)
minTenure / maxTenurenumberYears in the current role
minYearsExperience / maxYearsExperiencenumberTotal years of experience
recentlyChangedJobsbooleanOnly people who recently started a new role
companyNames / pastCompanyNamesstring[]Current or past employer names (fuzzy)
companyDomainsstring[]Current company website domains
industries, companyTypes, companyHqCountriesstring[]Current company industry, type, HQ country
headcountRangesstring[]Current company size, exact values: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+
locations, states, countries, continentsstring[]Person location: free-text (fuzzy), states/regions (fuzzy), full country names like "United States", continents
fullNamestringPerson full name (fuzzy)
languages, skills, schools, degrees, fieldsOfStudystring[]Profile attributes (schools, degrees and fields of study are fuzzy)
hasVerifiedEmailbooleanOnly people with a verified business email at their current company
excludeExistingbooleanHide people already saved as workspace leads, and never charge for them

Role and company filters all apply to the same, primary current position, so the company on each result always satisfies them. Someone whose main job is elsewhere is not matched through a secondary role.

Each result is a person record with a stable database id, name, headline, title, location, picture, current company (with domain, headcount, industries), pastCompanies, education, yearsOfExperience, and three fields worth special attention:

  • linkedinUrl: use this to add the person to a list or campaign.
  • contact: availability flags only (hasBusinessEmail, hasPersonalEmail, hasPhone). The actual email comes from enrichment.
  • saved: true when the person is already saved as a workspace lead. When that lead already has an email, the result also carries it in businessEmails, at no extra cost.

Searching companies

searchCompaniesDatabase works the same way (at least one filter, limit 1 to 100, cursor paging) and additionally accepts a sort with key (headcount, funding, founded, followers, lastRound) and dir (asc, desc; default desc). An unknown key is ignored and the results come back unsorted.

curl -X POST https://app.swarmhit.com/api/v1/database/companies/search \
  -H "Authorization: Bearer swh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "filters": {
      "industries": ["Software Development"],
      "countries": ["USA"],
      "minHeadcount": 50
    },
    "sort": { "key": "headcount", "dir": "desc" },
    "limit": 25
  }'

Company filters

FilterTypeMatches
namesstring[]Company names (fuzzy)
domainsstring[]Website domains
industriesstring[]Industries (use suggestions for valid values)
countriesstring[]ISO 3-letter HQ country codes, e.g. "USA"
headcountRanges, minHeadcount, maxHeadcountstring[] / numberCompany size. headcountRanges takes exact values: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+
minGrowth12mnumberMinimum 12-month headcount growth, percent
foundedAfter / foundedBeforenumberFounding year
minFundingUsd, lastRoundTypes, investorsnumber / string[]Funding raised, last round type, investors
technologiesstring[]Technologies in use

Note the country formats differ: people search takes full country names ("United States"), company search takes ISO 3-letter codes ("USA").

What your workspace supports

The filters above are the full vocabulary. The database behind a workspace can support only part of it, with fewer company sorts and suggestion fields. databaseCapabilities is free and returns, for people and companies, the filters, sorts (companies) and suggestionFields your workspace can use. A search that sets any other filter is rejected with a 400 that names it.

The people block also carries two flags. When emailAvailabilityKnown is false, search results omit contact until the person is enriched. When excludeSavedServerSide is false, saved people always come back flagged saved: true and are never charged, and excludeExisting has no effect on the results.

Finding valid filter values

Several filters only accept known values (industries, seniorities, headcount ranges, and so on). databaseSuggestions autocompletes them, and it is free: it consumes no credits.

curl -X POST https://app.swarmhit.com/api/v1/database/suggestions \
  -H "Authorization: Bearer swh_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "entity": "companies", "field": "industry", "query": "software" }'

Pass entity (people or companies) and a field. Omit query to get the most common values. data is an array of up to 15 strings. Supported fields:

  • People: title, keyword, seniority, department, function, company, industry, companyType, hqCountry, country, city, state, continent, language, skill, school, degree, fieldOfStudy, headcountRange
  • Companies: industry, country, headcountRange, lastRoundType, investor, technology, name

headcountRange returns a closed eight-value set on both entities. A field outside your workspace's suggestionFields is rejected with a 400.

Paging

Search responses carry a paging object with nextCursor (null when the result set is exhausted) and totalCount (when the database reports it). To get the next page, send the same request again with cursor set to the returned nextCursor. Filters must stay identical between pages. A cursor the database can no longer resume is rejected with a 400 asking you to start the search again.

curl -X POST https://app.swarmhit.com/api/v1/database/people/search \
  -H "Authorization: Bearer swh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "filters": { "titles": ["CTO"], "countries": ["United States"] },
    "limit": 25,
    "cursor": "NEXT_CURSOR_FROM_PREVIOUS_RESPONSE"
  }'

Since credits are charged per result returned, do not page further than you need. Fetching 4 pages of 25 costs the same as one page of 100, so there is no discount for large pages either: the lever is total results, and tighter filters are how you reduce it.

Enrichment

Search results are summaries. Enrichment fetches the full record for one person or company.

People

enrichPersonDatabase takes a linkedinUrl (required, a linkedin.com/in/... profile URL) and an includeEmail flag (default false). It returns the search result fields (without saved) plus summary, connections, followers, skills, websites and businessEmails. businessEmails lists verified business emails and is only filled with includeEmail: true (an empty array otherwise). The email lookup costs extra credits, charged only when it finds an email. Without includeEmail the response omits the contact availability flags.

curl -X POST https://app.swarmhit.com/api/v1/database/people/enrich \
  -H "Authorization: Bearer swh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "linkedinUrl": "https://www.linkedin.com/in/jane-doe",
    "includeEmail": true
  }'

To avoid paying for enrichments that find no email, filter your search with hasVerifiedEmail: true, or check the contact.hasBusinessEmail flag on the search result first.

When the person is already saved as a workspace lead, an email found with includeEmail is also stored on that lead. If the lead already has an email, includeEmail returns that email without looking it up again, so only the base enrichment is charged.

Companies

enrichCompanyDatabase resolves a company from its website domain (preferred), linkedinUrl, or name (at least one is required; when you pass several, the first in that order is used), and returns the full record in the same shape as a company search result: headcount and headcountGrowth12m, funding (total, last round amount/type/date, investors), estimatedRevenue range, followers, and openings (the number of open job listings).

curl -X POST https://app.swarmhit.com/api/v1/database/companies/enrich \
  -H "Authorization: Bearer swh_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "domain": "stripe.com" }'

Both enrich endpoints return 404 when nothing matches, and a miss is not charged.

Keeping results: lists and campaigns

Database results are transient. Swarmhit does not store them, and re-running a search bills again. As soon as a person is worth keeping, save them using the linkedinUrl from the result as the lead's profileUrl:

  • Add them to a list with addListLeads, then enroll the list later.
  • Or enroll them directly with addLeadsToCampaign; they are saved to the campaign's own list as well. Saving into a campaign's own list with addListLeads enrolls them too.

Both take up to 1,000 leads per request, and upsert the workspace lead and attach it in one call. Copy any other fields you want on the lead: firstName, lastName, headline and location keep their names, the result's title goes in jobTitle, company.name in company, and an enriched email in email. See Leads and lists for how leads work.

curl -X POST https://app.swarmhit.com/api/v1/lists/LIST_ID/leads \
  -H "Authorization: Bearer swh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "leads": [
      { "profileUrl": "https://www.linkedin.com/in/jane-doe", "firstName": "Jane", "lastName": "Doe", "company": "Acme" }
    ]
  }'

Two fields help you avoid duplicating work: set excludeExisting: true in your people search to hide anyone already saved as a workspace lead, and check the saved flag on each result before adding. The database can miss some saved people when applying excludeExisting (for example in a workspace with more than 25,000 leads); any that come back are flagged saved: true and not charged.

Credits and errors

Credit consumption in one place:

CallCredits
People or company search2 per result returned (saved people hidden by excludeExisting are not charged)
Person enrichment65 per matched person, plus 65 when includeEmail returns a verified business email
Company enrichment130 per matched company
Suggestions and capabilitiesFree

Credits come from the workspace's credit pool, or from its organization's pool when the workspace belongs to one. Once the pool is empty, searches and enrichments are refused with 400 and code: warning-no-credits.

Database endpoints return these errors:

  • 400 with code: warning-database-query: the search or lookup cannot run as sent, for example an unknown filter, a filter your workspace does not support, no filter with a value, an unknown headcountRanges value, an expired cursor, an unknown suggestion field, or an invalid LinkedIn profile URL. The message says what to fix.
  • 400 with code: warning-no-credits: the credit pool is empty.
  • 400 without a code: a malformed request, such as a limit outside 1 to 100, a missing linkedinUrl, or no domain, linkedinUrl or name on a company enrichment.
  • 404: an enrichment matched nothing. Nothing is charged.
  • 429 with code: rate_limited: the database is busy right now. Retry after a short delay.
  • 503 with code: unavailable: the database is temporarily unavailable. Retry later.

See Errors for the error envelope format.

On this page