Fiber AI
Search & discovery

Natural-language search

Ask in plain English and get a matching list of companies or people — plus a clear list of anything the query could not apply.

Natural-language search

View API reference · Tag Agentic search

We built natural-language search so you can describe who you want in a sentence and get back a list — the same structured company or people search you'd assemble by hand, without filling a filter form.

Try it in the dashboard or call POST /v1/nlp-search/run (slushieRun). Fiber picks companies or people (never both on one response) and pages with a single pageToken. You search the same 40M+ companies as structured search.

This is a list search, not a lookup. "Series B SaaS in NYC hiring RevOps" belongs here. "Jane Doe at Acme" or a LinkedIn URL belongs in Kitchen Sink.

What it does

  1. You send a free-form query (titles, stages, industries, locations, hiring signals, named employers, schools, languages, Open to Work, and similar).
  2. Fiber turns that sentence into structured search filters and runs the search.
  3. You get matching companies or people, parsedParams (how the sentence was read), unsupportedFilters (clauses that could not be applied), and a cursor for the rest of the match set.

Company-shaped questions return companies. Questions about people — including people at companies that match filters — return people. You do not choose the result type on slushieRun.

What you can call

OperationWhat it doesReturns
slushieRunRead a sentence and run the search it describesA page of companies or people, plus how the sentence was read
nlpSearchParseRead a sentence and stop — no searchThe structured filters and a suggestedAction, so you can check the interpretation before paying for results
multiSourceSearchRun the same kind of sentence across LinkedIn and Maps / the open webA page of companies or prospects, for local businesses with a thin LinkedIn footprint

slushieRun is the one you want by default. Reach for nlpSearchParse when you need to see the interpretation first, and multiSourceSearch when your targets are storefronts and clinics rather than tech companies.

What you send

slushieRun takes a single English sentence. Everything else is optional.

FieldNotes
queryThe sentence, up to 5,000 characters. Required on the first request, ignored once you pass a pageToken.
pageSize1–1,000, defaults to 25. Applies to whichever result type comes back.
pageTokenThe nextPageToken from the previous response. Send it alone to get the next page.
companyExclusionListIDsExclusion lists to subtract from company results, or to narrow the company side of a people search.
peopleExclusionListIDsExclusion lists to subtract from people results.
getDetailedEducationFills a detailedEducation array on each person — school URLs, locations. Slows the call down; leave it off unless you need it. People results only.
getDetailedWorkExperienceSame idea for employers, in detailedWorkExperience. People results only.

What you get back

FieldMeaning
results.resultTypecompanies or people. Read this first — it tells you which array is populated.
results.companies / results.peopleThe matches, in the same shape as structured search. Only one of the two is present.
parsedParamsThe filters your sentence became, and a queryType of structuredSearch, personLookup, companyLookup, or unprocessable. This is how you confirm we read you correctly.
unsupportedFiltersClauses we could not turn into a filter. They were dropped, not guessed.
autoLooseningsConstraints we relaxed because the exact combination matched nobody. First page onlynull on paginated requests.
noticesPlain-English warnings, such as an empty result set or the end of pagination. null when there is nothing to say.
nextPageTokenPass it back for the next page. Absent when you have everything.
searchIdStable across every page of one search — useful for logging and support.
chargeInfo.creditsChargedWhat this call actually cost. Authoritative.

nlpSearchParse returns parsedParams, unsupportedFilters, searchId, and a suggestedAction of companySearch, profileSearch, combinedSearch, personLookup, companyLookup, or none — your next step in one field.

const response: Response = await fetch("https://api.fiber.ai/v1/nlp-search/run", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    apiKey: process.env.FIBER_API_KEY,
    query: "YC W24 companies",
    pageSize: 25,
  }),
});

const payload: unknown = await response.json();

multiSourceSearch uses a two-step body: { request: "initial", query, pageSize } first, then { request: "subsequent", cursor } for each page. pageSize is locked for the session; a null nextCursor means you're done. For Maps-only local search, see Google Maps.

Rate limit on these routes: 120 requests per minute. Plan for a 60-second timeout on slushieRun — interpretation plus search can take longer than a typical lookup.

What you can ask for

These are some of the filters you can mix in one sentence — not an exhaustive list. If a clause can be a structured company or people filter, we apply it.

Companies

Ask forExample
Accelerator and batch"YC W24 companies"
Investor"Sequoia-backed Series B companies in the Bay Area"
Stage, industry, size"Series B SaaS companies with 50-200 employees"
Funding amount or recency"AI companies that raised over $20M in the last 6 months"
Founded date"SaaS companies founded after 2020"
Revenue"bootstrapped SaaS companies with $5M-$50M revenue"
Tech stack"companies using Kubernetes and Snowflake"
Open roles"Series B SaaS companies hiring RevOps"
HQ location"fintech companies based in NYC"

People

Ask forExample
Title and seniority"VPs of Sales at fintech companies in NYC"
Title exclusions"VPs of Sales …, not interns"
Named employer — current, past, or ever"people at Stripe", "ex-Google engineers", "people who have worked at Google"
People at companies that match company filters"engineers at Series B AI startups"
Open to Work"product managers open to work in NYC"
School, major, years of experience"Stanford CS grads, 4+ years, now senior engineers in the Bay Area"
Skills on the profile"engineers skilled in Go and Kafka"
Languages"people who speak Spanish at companies in Spain"
Recently joined / new in role"engineers who recently joined Series B startups"
Named-company exclusion (including never)"never worked at McKinsey"

Named past employer plus current company filters in the same sentence is supported — e.g. "ex-PMs at Google who are now founders at startups".

Examples

IntentExample
Accelerator + batch"YC W24 companies"
Named alumni now at a kind of company"ex-FAANG engineers now at startups"
Named past employer + current employer set"Stripe alumni who now work at YC companies"
Stage, industry, size, hiring"Series B SaaS companies in NYC with 50-200 employees hiring engineers"
Open to Work"product managers open to work in NYC"
Language + market"people who speak Spanish at companies in Spain"
School + seniority + location"Stanford CS grads, 4+ years, now senior engineers in the Bay Area"
Investor + stage + HQ"Sequoia-backed Series B AI companies in the Bay Area"

What is not supported

Anything we cannot turn into a filter is dropped, not guessed — and sometimes a nearby filter is applied instead. Always read unsupportedFilters and parsedParams before you trust the list.

You asked forWhat happens
Past employers described by company attributes (not a named company) — e.g. "alumni of Sequoia-backed companies", "people who used to work at Series A healthcare startups"Not a past-experience filter. Those clauses show up in unsupportedFilters.
"ex-YC founders" and similar (past role at an accelerator/investor set, not a named company)Often interpreted as founders at YC companies now, with an empty unsupportedFilters. If you mean alumni of YC companies, say that and check parsedParams.
People by department / job function — e.g. "engineering department", "marketing team"There is no department field. We match job titles or profile keywords instead (e.g. "Software Engineer", "Marketing Manager").
Remote / hybrid / on-site / willing to relocate as a person preferenceNot available on profiles. (Remote job postings on a company search are a different ask.) LinkedIn Open to Work is supported when you ask for it.
Subjective or intent language — e.g. "interested in AI", "looking to switch vendors", "high performers", "growth mindset"Dropped. We cannot filter on motives or performance.
Salary or compensation — e.g. "earning $200k+"Not a people/company filter. The clause is listed in unsupportedFilters; the rest of the query still runs.
Years of a specific skill — e.g. "3–5 years of Rust"Only total years of experience is a filter. Name the skill separately.
A specific person or company — name + employer, email, domain, or LinkedIn URLUse Kitchen Sink. slushieRun may route these to a lookup (queryType: personLookup / companyLookup, at most 50 people per request). Kitchen Sink is the dedicated path.
A full job description paste (long JD with Summary / Responsibilities / Requirements)This product expects a short targeting sentence. Pull title, skills, location, and years yourself, then search.
Greetings, posts, or anything that is not a company/people listparsedParams.queryType is unprocessable / suggestedAction is none.

A 200 with a list is not proof every clause was applied. Empty unsupportedFilters is not proof the interpretation matched your intent — check parsedParams.

On the first page only, if the original combination matches nobody, autoLoosenings may list constraints that were relaxed so you still get a page. Treat that as a different query than the one you typed.

Using it effectively

Parse before you run, then count before you page. The cheapest way to get a good list is a three-step loop that costs almost nothing to iterate. Call nlpSearchParse on your sentence and read parsedParams — 2 credits, no results. Take the companySearchParams or profileSearchParams it hands back and pass them straight into the structured count endpoints (companyCount / peopleSearchCount), which are free, to see how big the match set is. Only then call slushieRun, where you start paying per result. Rewriting a bad sentence at the parse step costs 2 credits; discovering the problem after pulling 500 profiles costs 500. See counting before you spend.

Name companies when you mean those companies. The strongest filters we can build from a sentence are the named ones. "Used to work at Stripe" becomes a past-employer filter and works exactly as you'd expect. "Alumni of Sequoia-backed companies" describes a set of employers by attribute, and there is no filter for that — it gets dropped. If you want that cohort, run it as two searches: find the companies first, then search people at them.

Say current, past, or ever — the default is not what you think. "At Google" reads as current employment. "Ex-Google" reads as past. "Has worked at Google" covers both. These three produce genuinely different lists, and the sentence is the only place you get to say which one you meant.

Read parsedParams on the first run of any new query shape. A 200 with 25 results looks like success whether or not we understood you. Once you have confirmed the interpretation for a query shape, you can trust it for the variants you send afterwards.

Pull pages with the token, not the query. Send pageToken on its own — query is ignored once a token is present, and interpretation is not charged again. Re-sending the sentence starts a fresh search and pays for interpretation a second time.

Iterate the sentence rather than fighting it. Every run is a fresh structured search, so tightening a query is a matter of restating it. If autoLoosenings came back populated, your original combination matched nobody and you are looking at a broader list than you asked for — tighten one constraint and run again rather than paging deeper.

One known person or company is not a search. A name plus employer, an email, a domain, or a LinkedIn URL belongs in Kitchen Sink. slushieRun can route those to a lookup, but you pay interpretation for the privilege.

Use cases

Build a sourcing pipeline from a role description. Say the role in one sentence — "Stanford or MIT CS grads, 4+ years, now senior backend engineers in the Bay Area" — and run slushieRun. Page with nextPageToken until it is absent, then take the LinkedIn URLs into Contact Reveal for email and phone. Add "open to work" to the sentence when you want the warm end of that list first.

Find accounts at a stage, then the people inside them. This is two searches, and the first one is the cheap one. Ask for the companies — "Series B SaaS companies in NYC with 50-200 employees hiring RevOps" — and you get a company list. Then ask for the people with the same company constraints in the sentence: "RevOps leaders at Series B SaaS companies in NYC". Feed your CRM's existing accounts in as companyExclusionListIDs so you are only paying for companies you don't already have.

Track a cohort over time instead of re-searching it. Run the sentence once to get the list, then hand those entities to Tracker and let it tell you when someone changes jobs or a company raises. A search answers "who matches today"; a tracker answers "who changed".

Screen an investor's or accelerator's portfolio. "YC W24 companies" or "Sequoia-backed Series B AI companies in the Bay Area" returns the batch as a list. Run nlpSearchParse first and pass the params to companyCount to see how big it is before you decide the page size.

Give an LLM agent a search tool it can actually use. slushieRun takes one string and returns structured results, which makes it a clean tool definition for Claude, Cursor, or your own agent — over REST or MCP. The agent writes the sentence; it does not have to learn a filter schema. Have it read unsupportedFilters and parsedParams back before it trusts the list, and notices to know when to stop paging.

Credits

OperationCost
slushieRun, first page2 credits for interpretation, plus 1 credit per company or person returned
slushieRun, later pages1 credit per result. Interpretation is not charged again.
nlpSearchParse2 credits per request, flat. No result charges — it returns no results.
multiSourceSearch2 credits per company or prospect found. Charged after the page completes.
companyCount, peopleSearchCountFree

Two things worth planning around. Interpretation is charged once per search, not once per page, so a 500-result pull costs 2 credits more than the results themselves — paging is the cheap part and re-sending the sentence is the expensive mistake. And multiSourceSearch is twice the per-result price of slushieRun, which is the trade for reaching businesses that have no real LinkedIn presence; use it when LinkedIn genuinely won't answer, not by default.

A first page that returns nothing still cost you interpretation. chargeInfo.creditsCharged on the response is authoritative. See Billing & credits.

Natural-language search is also available in the Fiber dashboard and through MCP.

On this page