Skip to content
SearchLeads/DevelopersGet API key
Documentation v1
DEVELOPER DOCUMENTATIONREST API · v1

Async exports

Create an export from a search ID and poll for completion.

POST/functions/v1/api-export-create

Preview before creating an export

Optional: POST api-export-preflight or call MCP preview_export with the same export intent. Requires export scope (hosted MCP also requires mcp). Preview is available for both People and Company search IDs.

curl -X POST "https://ttzqldekaizydrdmirpn.supabase.co/functions/v1/api-export-preflight" \
  -H "Content-Type: application/json" \
  -H "x-searchleads-api-key: sl_live_your_full_api_key_here" \
  -d '{"search_id":"SEARCH_ID_FROM_SEARCH_RESPONSE","requested_leads":3,"format":"csv","fields":["name","workEmail"],"saveContacts":true}'

Allowed JSON keys: search_id (required owned, unexpired successful search UUID), requested_leads (positive integer), format (csv only), fields (array of column keys), and saveContacts (JSON boolean). Omitted row count uses the smaller of the account limit and search snapshot count. Omitted columns use the safe-core default without email. Saving uses the current completed-export default; preview itself never saves records. Company requests must use Company column keys, for example name and country.

A valid preview returns HTTP 200 with can_export, blockers (code and message), requested_leads, max_exportable_rows, fields (normalized keys and readable labels), saving, credits, limits and delivery. Check can_export and resolve blockers before calling export creation. The server never silently reduces an explicitly requested row count.

  • availability.rows_at_search is the search-time snapshot, not a fresh live count. as_of, snapshot_age_seconds and expires_at show its age/expiry. count_exact: true means exact at search time; false means a lower bound; null means historical exactness is unknown. An approximate count does not prove the full audience size.
  • credits.maximum_required_hold is the maximum credit hold calculated with current prices and selected paid fields. credits.spendable and credits.sufficient describe the current spendable balance. Final charges depend on delivered email/phone data and existing entitlements; the maximum hold is not a promised final charge.
  • credits.charged and credits.reserved are zero. Preview creates no search session, export job, provider request, file or saved membership. Saving adds no separate surcharge.
  • Preview reserves neither credits nor records. Prices, balance, membership, limits and readiness may change; start_export / api-export-create always revalidate and may reject a previously ready preview. Preview is optional and is not a reservation token.
  • Preview uses one shared per-minute request slot across REST/MCP, has no daily cap, and returns the normal rate-limit headers in REST. Export creation and status remain unlimited by those customer request quotas. MCP uses result.isError for HTTP failures; HTTP 200 with can_export: false is a readable blocked preview, not a transport error.

Readiness blockers include insufficient_export_credits, export_size_exceeded, export_size_exceeds_search_total, search_total_zero, max_concurrent_jobs_reached, payment review, and unavailable delivery. Invalid/unsupported fields return 400; invalid typed values or format return 422; missing access returns 401/403; foreign/unknown search IDs return 404; expired IDs return 410; missing successful snapshots return 409; quota exhaustion returns 429; failed dependency reads return 503. Retry 429/503 with backoff; rerun a paid search only when a new search ID is intentionally needed.

The asynchronous export API uses a search_id returned by people or company search. It runs from page 0 of the saved canonical query. New searches also pin their server sort, so a limited export follows the search order. Existing snapshots without a pinned sort retain their original traversal. Create a job, then poll its status. Your client does not need to send a provider callback.

curl -X POST "https://ttzqldekaizydrdmirpn.supabase.co/functions/v1/api-export-create" \
  -H "Content-Type: application/json" \
  -H "x-searchleads-api-key: sl_live_your_full_api_key_here" \
  -H "Idempotency-Key: my-export-2026-10-06" \
  -d '{
    "search_id": "SEARCH_ID_FROM_SEARCH_RESPONSE",
    "requested_leads": 5000,
    "format": "csv",
    "fields": ["name", "title", "workEmail"],
    "delivery_email": "ops@yourcompany.com"
  }'

curl -X GET "https://ttzqldekaizydrdmirpn.supabase.co/functions/v1/api-export-status?job_id=JOB_ID" \
  -H "x-searchleads-api-key: sl_live_your_full_api_key_here"

You can provide an Idempotency-Key header or idempotency_key body field. If omitted, SearchLeads generates and returns one. Status polling is read-only.

Choose requested_leads between 1 and the smaller of your account's maximum and the saved search response's results.totalElements. Use the total, not results.content.length, which is only the current page. Do not create an export when the search is empty. A reported lower-bound or approximate total does not establish the entire audience size; the saved snapshot count is the exportable limit for that search_id.

The 5,000-row example above assumes at least 5,000 available records. An oversized request returns REST HTTP 422 with code: "export_size_exceeds_search_total" and available_records; MCP returns the same payload with result.isError: true. This refusal does not create an export job or hold additional export credits. For example, if available_records is 1, create a new intentional one-row request with a fresh idempotency key. Keep the original key and identical body when retrying an unchanged request after a timeout.

Choose fields explicitly. Omitting it uses a smaller safe-core API default that does not include email. Check capabilities for supported column keys, current maximum rows, job limits, and formats. Export credit cost depends on selected data and account configuration.

Save or do not save exported records

REST export creation and MCP start_export both accept saveContacts as a JSON boolean. It applies to both People and Company exports despite the parameter's name.

ValuePeople exportCompany export
trueAdd completed exported people to this account's Saved ContactsAdd completed exported companies to this account's Saved Companies
falseLeave existing saved membership unchangedLeave existing saved membership unchanged
OmittedUse the configured People save defaultUse the configured Company save default

Check authenticated capabilities exports.saveRecordsBySearchType.people or .company for enabled, default, and the parameter name. If saving is disabled, the current service uses false even when true was requested; do not promise that those records were saved. Set an explicit boolean whenever your workflow needs a particular choice. false does not remove previously saved records.

{
  "search_id": "REPLACE_WITH_RETURNED_SEARCH_ID",
  "requested_leads": 1,
  "fields": ["name", "linkedin"],
  "format": "csv",
  "saveContacts": true,
  "idempotency_key": "REPLACE_WITH_ONE_KEY_FOR_THIS_EXPORT_INTENT"
}

The saved search determines People versus Company and preserves any Saved-only or Net-New scope. Saving occurs as export records are completed/committed, rather than when the search runs. Wait for completion and saved-membership synchronization before expecting the records to disappear from a fresh Net New search. Saving does not alter an already-created search snapshot; run a new scoped search to observe the updated saved set. Previous exports are not backfilled. Keep the same body and key for an uncertain retry; intentionally changing the save choice creates a new export intent and requires a new key.

Export behavior and pricing

  • API clients make two kinds of calls: create a job, then poll status. Provider callbacks are internal server-to-server messages. Status polling is read-only.
  • UI, API, and MCP use the same configured fractional-credit prices for equivalent exports. Company exports use the configured company price per delivered row; for example, at 0.1 credit per row, one row costs 0.1 and eleven rows cost 1.1. Credit calculations retain two decimal places instead of rounding each export up to a whole credit. Read your account's current pricing and available/held credits before exporting.
  • The export begins at page 0 of the saved canonical search, even if the search_id came from a later search page. Use the ID before its search_id_expires_at time.
  • A job holds the maximum selected-field charge, then settles based on delivered data. People rows with a valid Work Email use the account's export base cost plus its Work Email cost. A row with no requested paid contact data costs 0.5 credit when that policy is enabled. API and MCP exports have no separate channel surcharge.
  • The account's saved default export template can override built-in Bulk Export selections. Explicit fields make integrations predictable.
  • If a provider job is stuck before pickup, SearchLeads support can retry dispatch internally; clients do not need an extra callback or retry parameter.

The capabilities endpoint reports allowed formats, maximum requested leads, concurrent jobs, and explicit unlimited create/status request quotas. Create and status requests have no customer request quotas and do not consume the shared search allowance. Concurrent jobs, credits, ownership checks and maximum export size remain enforced.

Available export columns

The live tables include every current People and Company column key (the exact CSV header), display label, group, kind, and built-in Bulk Export default. An API key loads your account's exact export permissions.

Legacy export integrations may accept additional historical column aliases. New integrations should use the current exports.fieldsBySearchType keys and must not infer additional fields from old CSV files.

Live export column reference

Explore the current CSV columns and export limits directly from the API.

Public catalog
Use your account’s contract Optional

Load your exact permissions and limits with a full API key. Your key stays in this page’s memory and is sent only to the SearchLeads API.

Formats
csv
CSV row limit
100000
Concurrent jobs
10
Search ID lifetime
1440 min
Create requests: Unlimited
Status requests: Unlimited

Concurrent jobs: 10. Credit billing and export size limits still apply.

People columns

73 of 73 columns shown. Default columns are marked.

CSV header / request keyDisplay labelGroupKindBulk default
jobLocationJob LocationProfiletext—
educationCompletionYearEducation Completion YearExperiencelist—
emailLastVerifiedDateEmail Last Verified DateContactdate—
contactMethodAvailableAny Contact Method AvailableContactboolean—
personaPersonaProfilelist—
linkedinConnectionsLinkedIn ConnectionsProfilenumber—
patentsPatentsExperiencelist—
publicationsPublicationsExperiencelist—
companyHasCioCompany Has CIODigital signalsboolean—
companyHasCisoCompany Has CISODigital signalsboolean—
companyLocationCountCompany Number of LocationsDigital signalsnumber—
companyOrganicTrafficCompany Organic TrafficDigital signalsnumber—
companyPaidTrafficCompany Paid TrafficDigital signalsnumber—
companySicCodesCompany SIC CodesDigital signalslist—
companyLegalTypeCompany Legal StructureDigital signalstext—
companyWebsiteForSaleCompany Website for SaleDigital signalsboolean—
workEmailWork EmailContactcontactYes
personalMobilePersonal MobileContactcontact—
emailStatusEmail StatusContacttextYes
workEmailAvailableWork Email AvailableContactboolean—
personalMobileAvailablePersonal Mobile AvailableContactboolean—
nameFull NameProfiletextYes
firstNameFirst NameProfiletextYes
lastNameLast NameProfiletextYes
headlineHeadlineProfiletextYes
titleJob TitleProfiletextYes
senioritySeniorityProfiletextYes
departmentDepartmentProfiletextYes
linkedinLinkedIn URLProfiletextYes
locationLocationProfiletextYes
cityCityProfiletextYes
stateStateProfiletextYes
countryCountryProfiletextYes
jobStartDateJob Start DateExperiencedate—
skillsSkillsExperiencelist—
certificationsCertificationsExperiencelist—
personalWebsitePersonal WebsiteContacttext—
educationDegreeEducation DegreeExperiencelist—
companyCompany NameCurrent companytextYes
companyDomainCompany DomainCurrent companytextYes
companyWebsiteCompany WebsiteCurrent companytextYes
companyLinkedinCompany LinkedIn URLCurrent companytextYes
companyLocationCompany LocationCurrent companytextYes
companyDescriptionCompany DescriptionCurrent companytext—
companyIndustryCompany IndustryCurrent companytextYes
companyNaicsCompany NAICSCurrent companytextYes
companyTypeCompany TypeCurrent companytextYes
companyEmployeesCompany EmployeesCurrent companynumberYes
companyRevenueCompany RevenueCurrent companynumberYes
companyFoundedYearCompany Founded YearCurrent companynumberYes
companyHeadcountGrowthCompany Headcount GrowthGrowth and hiringnumber—
companyDepartmentEmployeesCompany Employees by DepartmentGrowth and hiringlist—
companyHiringDepartmentsCompany Hiring DepartmentsGrowth and hiringlist—
companyOpenRolesCompany Open RolesGrowth and hiringlist—
companyLastFundingTypeCompany Last Funding TypeFundingtext—
companyLastFundingAmountCompany Last Funding AmountFundingnumber—
companyTotalFundingCompany Total FundingFundingnumber—
companyLastFundingDateCompany Last Funding DateFundingdate—
companyLeadInvestorsCompany Lead InvestorsFundinglist—
companyInvestorCountCompany Investor CountFundingnumber—
companyTechnologiesCompany TechnologiesTechnologylist—
companyKeywordsCompany KeywordsTechnologylist—
companyTrafficCompany TrafficDigital signalsnumber—
companyAdvertisingSpendCompany Advertising SpendDigital signalsnumber—
companyMobileAppPresenceCompany Mobile App PresenceDigital signalsboolean—
companyWebAppPresenceCompany Web App PresenceDigital signalsboolean—
companyAppRatingCompany App RatingDigital signalsnumber—
companyAppReviewsCompany App ReviewsDigital signalsnumber—
companyIosAppRatingCompany iOS App RatingDigital signalsnumber—
companyGooglePlayAppRatingCompany Google Play App RatingDigital signalsnumber—
companyIosAppReviewsCompany iOS App ReviewsDigital signalsnumber—
companyGooglePlayAppReviewsCompany Google Play App ReviewsDigital signalsnumber—
companyAppDownloadsCompany App DownloadsDigital signalsnumber—

Additional People column mappings

Export keyCSV value sourceExport section
jobLocationjobLocation.city, .state, .country; never personal or HQ geographyProfile
educationCompletionYearAll education.endYear valuesExperience
emailLastVerifiedDateemailLastVerifiedAtContact
contactMethodAvailableisReachableContact
personapersonaProfile
linkedinConnectionslinkedinConnectionsProfile
patentspatentsExperience
publicationspublicationsExperience
companyDescriptionorganization.about, then legacy company description fieldsCurrent company

Company signal columns and their source fields are listed in Filters and option discovery. Their People equivalents use the organization. prefix and belong to Digital signals. Experience and Digital signals columns follow the account's enabled export-section switches. Request exports.fieldsBySearchType for the exact allowed set before creating an export. Boolean values export as true/false, zero remains 0, absent values remain blank, and lists use | between values. Industry codes retain leading zeros in the CSV text; import those columns as text in spreadsheets.

Company city, state, and country keep their existing primary and legacy values and use the corresponding headquarters value when otherwise blank. Headquarters regions such as APAC are not substituted for a missing State. These fallbacks do not change People location columns or the search's location semantics.

Company keyword filters also search company descriptions. Select the optional companyDescription column in People exports to inspect that text. Missing descriptions remain blank. This field is available through the same UI, API and MCP column catalog and does not change existing export layouts.

App-store metrics

App Rating and App Reviews filters can match either iOS or Google Play. The existing generic columns (appRating, appReviews, and their company-prefixed People equivalents) keep their first-available behavior: iOS is preferred, then Google Play, then legacy sources. A generic value may therefore fall outside your range when the other store matched.

Select iosAppRating, googlePlayAppRating, iosAppReviews, and googlePlayAppReviews for Company exports. People exports use companyIosAppRating, companyGooglePlayAppRating, companyIosAppReviews, and companyGooglePlayAppReviews. These map directly to appStore.iosRating, appStore.playRating, appStore.iosReviews, and appStore.playReviews, with organization. added for People. Missing platform values stay blank; zero remains 0. Only selected columns are added, in your requested order.

Job lifecycle and download

A successful create returns HTTP 202 with job_id and status. Poll api-export-status?job_id=... about every five seconds; polling more frequently does not make jobs complete faster. The status body includes job_id, status, requested_leads, effective_leads, held_credits, final_credits_charged, refunded_credits, download_url, download_expires_at, and error_message; some values remain null until completion.

StatusNext step
queued, processingContinue polling with a bounded timeout.
completedGET the non-null download_url to retrieve the file, or use google_sheet_url for a Sheets export.
failed, cancelledStop polling and inspect error_message. Do not assume a usable file exists.

CSV download URLs are signed and expire; the current in-house URL lifetime is five minutes. Poll status again for a fresh URL if it expires. Treat the URL as a bearer secret. If a create request times out, retry with the same Idempotency-Key and identical body to avoid duplicate jobs. If your polling timeout expires, retain the job ID and resume status polling later.

This Python example uses the standard library. Set SEARCHLEADS_API_KEY, SEARCHLEADS_SEARCH_ID, and SEARCHLEADS_DELIVERY_EMAIL in your environment. It assumes the saved search has at least two available records, creates a two-row CSV with explicitly selected, non-email columns, then downloads it after completion. For a one-result search, intentionally change the row count to 1 before creating the job. This is a real export and consumes credits according to your account policy. The API base below targets the current documentation environment.

import json
import os
import time
import urllib.request
import uuid
from pathlib import Path

base = "https://ttzqldekaizydrdmirpn.supabase.co/functions/v1"
key = os.environ["SEARCHLEADS_API_KEY"]
idempotency_key = str(uuid.uuid4())  # Persist and reuse if create is retried.

def request(path, payload=None, extra_headers=None):
    headers = {"x-searchleads-api-key": key, **(extra_headers or {})}
    data = None if payload is None else json.dumps(payload).encode()
    if data is not None:
        headers["Content-Type"] = "application/json"
    req = urllib.request.Request(base + path, data=data, headers=headers)
    with urllib.request.urlopen(req, timeout=30) as response:
        return json.load(response)

job = request("/api-export-create", {
    "search_id": os.environ["SEARCHLEADS_SEARCH_ID"],
    "requested_leads": 2,
    "format": "csv",
    "fields": ["name", "title"],
    "saveContacts": False,
    "delivery_email": os.environ["SEARCHLEADS_DELIVERY_EMAIL"],
}, {"Idempotency-Key": idempotency_key})
job_id = job["job_id"]
for _ in range(120):
    state = request("/api-export-status?job_id=" + job_id)
    if state["status"] == "completed":
        if not state.get("download_url"):
            raise RuntimeError("Completed job has no CSV download URL")
        with urllib.request.urlopen(state["download_url"], timeout=60) as file:
            Path("searchleads-export.csv").write_bytes(file.read())
        break
    if state["status"] in ("failed", "cancelled"):
        raise RuntimeError(state.get("error_message") or state["status"])
    time.sleep(5)
else:
    raise TimeoutError("Resume polling job " + job_id + " later")

The request fields entries and CSV headers use exact keys such as companyHasCio. Display labels such as Company Has CIO are for readability. Read each filter's exportVerification for related CSV keys and verification limitations.

For Company exports with a supported included Company Location filter, location, city, state, and country use the same selected primary or headquarters address as searchLocation in search results. A headquarters match therefore exports headquarters geography even if the main address is in another country. Missing components of that address remain blank; components from different offices are not combined. A CSV shows one address, so ALL across separate locations cannot be fully verified from that tuple alone. Previously generated files are not rewritten.

In the UI, Re-run search restores search criteria. Repeat export restores stored columns, column order, row count and save choice, then opens a review dialog after the search succeeds. It does not submit an export automatically. Current availability, credits and enabled columns are checked again. Older exports without complete stored settings cannot restore those settings; rerun their search and choose new export settings instead.

On this page