/v1/searches/runRun a search plan
search:readRun a query plan directly against the talent corpus and get back result skeletons. A plan is 1 to 4 lanes run in parallel (semantic search over repositories, BM25 over repositories or user text, an attribute-ranked user lane, semantic search over LinkedIn profiles), fused by reciprocal rank: someone surfaced by two lanes ranks above someone surfaced by one, and there are no weights to tune because no weighting the index cannot execute is offered. Billed 1 credit per skeleton ACTUALLY RETURNED; limit is the price ceiling and a run that returns nothing costs nothing. A skeleton is identity plus evidence: name, handle, avatar, headline, location, devrank tier and followers, and the repositories that matched with the reason they matched. Everything richer (contribution garden, AI summaries, verified email, LinkedIn detail) is a facet bought per developer on POST /v1/developers, which is unchanged. There is no cursor: pass the ids you have already seen in excludeDeveloperIds. Counts are never exact, because an exact count over this corpus cannot be computed inside a request. Freshness is disclosed rather than assumed: asOf carries the crawl time on the profile, devrank is a weekly batch, and lastSeen is an approximation from repository crawl times. Send a natural-language query instead of a plan to have the plan written for you: planning is free and cached, the plan that ran is echoed back with its caveats, and only the rows bill.
Request body RunSearchRequest
planobjectThe query plan to run: 1-4 parallel lanes, shared user filters, RRF fusion.
intentstring requiredmax 300 charslanesarray of one of requiredmin 1 items, max 4 itemsOption 1kindstring requiredusers.bm25textstring requiredmin 1 chars, max 200 chars
Option 2kindstring requiredusers.rankattributestring requiredcreatedAtdirectionstring requiredascdesc
Option 3kindstring requiredrepos.anntextstring requiredmin 1 chars, max 500 charsrepoFiltersarray of arraymax 6 items
Option 4kindstring requiredrepos.bm25textstring requiredmin 1 chars, max 200 charsrepoFiltersarray of arraymax 6 items
Option 5kindstring requiredlinkedin.anntextstring requiredmin 1 chars, max 500 charsliFiltersarray of arraymax 6 items
Option 6kindstring requiredusers.anntextstring requiredmin 1 chars, max 500 chars
userFiltersarray of array default: []max 8 itemspostobjectminDevrankTierstringEliteRareSolid
fuseobject default: {"method":"rrf","k":60}methodstring requiredrrfkinteger default: 60min 1, max 200
querystringNatural language, planned server-side and then run. Planning is free and cached; you are still billed only for the rows returned. Send `plan` instead when you want to control the plan yourself. Exactly one of the two.
max 20000 charslimitinteger default: 25Maximum skeletons to return, and therefore the price ceiling: you are billed 1 credit per row actually returned, so a run that yields nothing costs nothing.
min 1, max 100excludeDeveloperIdsarray of string default: []Ids to keep out of this run. This is how "get me more" works — there is no cursor; the ids compile to a native NotIn filter.
max 5000 items
Responses
200The result skeletons, the plan that ran, and its billresultsarray of object requiredmax 100 itemsskeletonSearchSkeleton requiredidstring requiredThe BountyLab user id (github-users-v3.id).
max 64 charsloginstring requiredmax 200 charsnamestring requiredmax 200 charsavatarUrlstring requiredmax 2048 charsheadlinestring | null requiredmax 2048 charslocationstring | null requiredmax 200 charscountrystring | null requiredmax 200 charslinksobject requiredgithubstring requiredmax 2048 charslinkedinstring | null requiredmax 2048 chars
crackedboolean requireddevrankobject | null requiredtierstring requiredmax 200 charsscorenumber requiredasOfstring | null requiredWhen the devrank row was computed. Always null today: users_elo carries no timestamp column. The ceiling is the weekly batch, so treat this as up to 7 days old.
max 200 chars
followersnumber | null requiredmatchedReposarray of SearchSkeletonRepo requiredmax 100 itemsfullNamestring requiredmax 200 charsstarsnumber requiredlanguagestring | null requiredmax 200 charswhystring | null requiredWhy this repo is here: the lane and its distance/score against the lane text. Null when the repo is the person’s top work rather than a match.
max 2048 chars
lastSeenstring | null requiredAPPROXIMATE: the newest crawl time among the matched repos. There is no activity timestamp on a user row, so this is a proxy, not a last-active date.
max 200 charsscorenumber requiredThe fused RRF score. Monotonic within THIS response only.
lanesarray of string requiredmax 100 itemsasOfobject requiredprofilestring | null requiredmax 200 charslinkedinstring | null requiredmax 200 chars
countStatusobject requiredHow many matches we can honestly claim. Only ever `atLeast`: an exact count over a 100M+ row corpus times out, so we never run one.
kindstring requiredatLeastnnumber required
appliedobject requiredplanobject requiredintentstring requiredmax 300 charslanesarray of one of requiredmin 1 items, max 4 itemsOption 1kindstring requiredusers.bm25textstring requiredmin 1 chars, max 200 chars
Option 2kindstring requiredusers.rankattributestring requiredcreatedAtdirectionstring requiredascdesc
Option 3kindstring requiredrepos.anntextstring requiredmin 1 chars, max 500 charsrepoFiltersarray of arraymax 6 items
Option 4kindstring requiredrepos.bm25textstring requiredmin 1 chars, max 200 charsrepoFiltersarray of arraymax 6 items
Option 5kindstring requiredlinkedin.anntextstring requiredmin 1 chars, max 500 charsliFiltersarray of arraymax 6 items
Option 6kindstring requiredusers.anntextstring requiredmin 1 chars, max 500 chars
userFiltersarray of array default: []max 8 itemspostobjectminDevrankTierstringEliteRareSolid
fuseobject default: {"method":"rrf","k":60}methodstring requiredrrfkinteger default: 60min 1, max 200
warningsarray of string requiredWhat the run cannot honestly promise. Empty when you sent your own plan: these are the planner’s caveats about a natural-language `query`.
max 100 itemsscopestring required`linkedin_linked_subset` whenever a LinkedIn lane contributed: that lane sees ~12% of the corpus, and the UI must say so.
full_corpuslinkedin_linked_subset
billingobject requiredtotalnumber required
401No or invalid credentialcodestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.
403Missing search:readcodestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.
422A lane is not available yet (LANE_UNAVAILABLE), or the query could not be planned (UNPLANNABLE)codestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.
502The planner is unavailablecodestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.