Search with filters
View as MarkdownPOST /v1/people/search. An exact filter set in, a deterministic page of people out, one credit a call. Every field, every allowed value, and how to paginate.
An exact filter set in, a page of people out. No model runs and nothing is ranked, so the same filters return the same page tomorrow, which is what makes this the one to build a pipeline on.
/api/v1/people/search1 creditDeterministic, repeatable, cursor-paginated. A filter set in, a page of people out.
queryobjectrequired- The filter set. Every field is optional and at least one is required.
limitintegeroptional- How many to return, 1 to 100. Defaults to 25.
cursorstringoptional- The
nextCursorfrom a previous response.
curl https://www.refolk.ai/api/v1/people/search \
-H "Authorization: Bearer $REFOLK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": {
"titleIncludes": ["engineer"],
"skills": ["Rust"],
"countries": ["Germany"],
"seniorityLevels": ["Senior", "Director"],
"minYearsExperience": 6
},
"limit": 25
}'Filters are combined with AND: the query above means senior or director-level engineers, in Germany, with Rust on file, and at least six years in.
keywordsstringoptional- Free text, matched against the headline.
titleIncludesstring[]optional- Job titles to include, matched as substrings.
"engineer"catches every kind of engineer. titleExcludesstring[]optional- Job titles to exclude.
companyNamesstring[]optional- Employers, by their common name rather than their legal one.
companyIndustriesstring[]optional- The industry the employer is in.
seniorityLevelsstring[]optional- One or more of
Owner,Founder,CXO,Partner,VP,Director,Manager,Senior,Entry. Anything else is a400. headcountRangesstring[]optional- Employer size, one or more of
1-10,11-50,51-200,201-500,501-1000,1001-5000,5001-10000,10001+. locationsstring[]optional- Metro areas, spelled the way a profile would:
"San Francisco Bay Area". countriesstring[]optional- Country names, such as
"Germany". skillsstring[]optional- Skills listed on the profile.
minYearsExperiencenumberoptional- Lower bound on total years of experience.
maxYearsExperiencenumberoptional- Upper bound on total years of experience.
recentlyChangedJobsbooleanoptional- Only people who started somewhere new recently.
verifiedEmailOnlybooleanoptional- Only people with a verified work email on file.
currentEmployersOnlybooleanoptional- Defaults to
true. Setfalseto match the employer filters against past roles too, which is how you find people who used to be somewhere.
An unknown value in an enum field comes back as a 400 naming the field, the
value, and the list it should have come from. Nothing is charged for a request
that never ran.
Pagination
Pages are walked with an opaque cursor: pass back the nextCursor you were
given, change nothing else, and a null one means you have reached the end.
async function everyone(query: object) {
const all = [];
let cursor: string | null = null;
do {
const res = await fetch("https://www.refolk.ai/api/v1/people/search", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.REFOLK_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ query, limit: 100, cursor }),
});
const page = await res.json();
all.push(...page.profiles);
cursor = page.nextCursor;
} while (cursor);
return all;
}Each page is 1 credit, so a walk over a large result
set costs one credit per 100 people. Check totalCount on the first
page before committing to the walk.
Turning a sentence into a filter set
Write the brief once in English, keep the filter set it produces, and run the structured search on a schedule from then on. One credit, and no search runs.
/api/v1/people/translate1 creditA sentence in, the filter set the structured search takes out. Nothing is searched.
promptstringrequired- Who you are looking for, in English.
currentQueryobjectoptional- An existing filter set to amend rather than replace.
curl https://www.refolk.ai/api/v1/people/translate \
-H "Authorization: Bearer $REFOLK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "senior platform engineers at mid-size fintechs in Berlin"}'The result is the filter set and nothing else, so you can show it to somebody, store it, diff it against the last one, or edit a field by hand before you spend anything on results.
When to reach for the other one instead
Filters cannot express "shipped Rust in production", "maintains something people depend on", or "was an engineer before founding". Those are judgements about evidence, and they are what the plain English search is for. Use filters when you know the criteria and want them applied the same way every time.
Try it on the search you came here for
Stop building boolean strings. Just describe the person.
Type one sentence. I plan the search, read GitHub, public LinkedIn and Crunchbase records, and the open web as it is right now, and hand back a ranked list with the reason next to every name.
01Describe them
One plain sentence. Role, city, stack, stage, whatever matters to you.
02I read the web live
GitHub, public LinkedIn and Crunchbase records, the open web. Not a database that went stale last quarter.
03You read the shortlist
Ranked, with the reasoning under every name. Open a profile, ask a follow-up, narrow it down.
- Staff backend engineers in NYC who shipped Rust in production
- Series A fintechs in SF under 50 people, growing headcount this year
- Maintainers of fast-growing Rust web frameworks on GitHub
- No boolean, no filters, no seat to buy. One box.
- Read at search time, so a profile updated yesterday counts today.
- Every step visible as it runs, every name with its reason.
500 free credits on sign-up. No card, no demo call. See real searches.